Slide 1

Slide 1 text

CONSTRUYENDO UNA API REST CON PYTHON Y MONGODB César Suárez Ortega II Jornadas Técnicas UEx – CIEMAT: Introducción a NoSQL con MongoDB 9 – 11 de Febrero, 2016

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Software Developer / Researcher César Suárez Ortega tharandur csuarez

Slide 5

Slide 5 text

Software Developer / Researcher César Suárez Ortega

Slide 6

Slide 6 text

POWERED BY

Slide 7

Slide 7 text

Software Developer / Researcher César Suárez Ortega

Slide 8

Slide 8 text

Índice Qué es una API REST  Python + MongoDB = PyMongo Práctica: API para una tienda online

Slide 9

Slide 9 text

APIs REST

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

APIs REST  API: Application Programming Interface.  REST: Representational State Transfer. Arquitectura cliente-servidor. Comunicación mediante protocolo HTTP. CLIENTE SERVIDOR Petición HTTP Respuesta HTTP

Slide 12

Slide 12 text

Petición HTTP  Se hace a una URL (http://api.com/foo). Métodos de petición:  GET: Obtiene datos.  POST: Edita datos  PUT: Añade datos  DELETE: Borra datos. Cabeceras, cuerpo (JSON), versión, etc.

Slide 13

Slide 13 text

Respuesta HTTP Cuerpo (JSON) Código de respuesta  200: OK  4XX: Error en la petición.  400: Petición mal formada.  401: Problema en autenticacións.  403: Petición rechazada.  404: Recurso no encontrado.  5XX: Error en servidor (500). Cabeceras, versión, etc.

Slide 14

Slide 14 text

¿Por qué REST?

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

http://getpostman.com

Slide 17

Slide 17 text

PyMongo

Slide 18

Slide 18 text

Python

Slide 19

Slide 19 text

Python 101 def print_animals(print_it): if print_it == True: for animal in ["dog", "cat", "mouse"]: print "{0} is a mammal".format(animal) Lenguaje interpretado.  No usa llaves: Identación. Muy muy legible.  No hace falta saberlo para la práctica. https://learnxinyminutes.com/docs/python/

Slide 20

Slide 20 text

http://bit.ly/juc-pymongo-code

Slide 21

Slide 21 text

JSON = Python Dictionaries product = { "type": "videogame", "title": "The Witness", "price": 36.99, "description": "Best game ever", "platforms": ["PC", "PS4"], "reviews": [ { "user": "csuarez", "rating": 5, "comment": "This game changes my life *_*" }, { "user": "jtriguero", "rating": 5, "comment": "I see puzzles everywhere 8)" } ] }

Slide 22

Slide 22 text

PyMongo 101 # Importamos PyMongo from pymongo import MongoClient # Creamos el cliente client = MongoClient("0.0.0.0", 27017) # Obtenemos una base de datos db = client.shop # Obtenemos una colección collection = db.catalog

Slide 23

Slide 23 text

Insertando datos from bson.objectid import ObjectId # Definiendo un documento item = {"description": "our first item"} # Insertando un documento objectid = collection.insert_one(item) # De ObjectId a string objectid_as_string = str(objectid) # De string a ObjectId objectid_is_back = ObjectId(objectid_as_string) # Array de documentos lots_of_items = [ {"description": "another item"}, {"description": "moar items"} ] # Insertando un array de documentos array_of_object_ids = collection.insert_many(lots_of_items)

Slide 24

Slide 24 text

Consultando datos I # Obteniendo el primer documento document = collection.find_one() print document["description"] # Usando queries y proyecciones document = collection.find_one({"description": "another item"}, "fields"={"_id": False}) # ¡Organiza tu código! document = collection.find_one( {"description": "another item"}, fields={"_id": False} ) # ¡En serio! >: document = collection.find_one( {"description": "another item"}, fields={"_id": False} )

Slide 25

Slide 25 text

Consultando datos II # Obteniendo varios documentos. ¡Devuelve un iterator! cursor = collection.find({}) for doc in cursor: print doc['description'] # Esto es lo mismo for doc in collection.find({}): print doc['description'] # Dot Notation for doc in collection.find({'field1.field2': 'whatever'}): print doc['field1']['field2'] # Filtrando por datos de un array for doc in collection.find({'some_array': 'value'}): print doc['some_array']

Slide 26

Slide 26 text

Consultando datos III # Ordenando resultados for doc in col.find({}).sort('field'): ... # Ignorando los dos primeros elementos for doc in col.find({}).skip(2): ... # Devolviendo sólo 5 resultados for doc in col.find({}).limit(5): ... # ¡Todo junto! for doc in col.find({}).skip(2).limit(5).sort('field'): ...

Slide 27

Slide 27 text

Consultando datos IV # Operadores ($lt, $lte, $gt, $gte) col.find_one({'stock': {'$lt': 100}}) #Operadores sobre arrays col.find_one({'tags': '$in': ['mongodb','nosql']}) #Operadores lógicos col.find_one({'$or': [ {'stock': {'$lt': 100}}, {'tags': '$in': ['mongodb','nosql']} ])

Slide 28

Slide 28 text

Agrupando datos: Aggregation # Obtenemos un sumatorio para cada valor del campo 'tags' collection.aggregate([ {'$unwind': '$tags'}, {'$group': { '_id': '$tags', 'total': {'$sum': 1} }} ]) # Resultado esperado [ { '_id': 'book', 'total': 2 }, { '_id': 'videogame', 'total': 4 } ]

Slide 29

Slide 29 text

Indexes from pymongo import ASCENDING #Creando un index col.create_index([("item_number", ASCENDING)]) #Usando el index for doc in col.find({}).hint(["item_number", ASCENDING]): print doc['description']

Slide 30

Slide 30 text

Actualizando datos I # Incrementando el valor de un documento col.update_one({"item_number": 5}, {"$inc": {"stock": 20}}) # Incrementando el valor de varios documentos col.update_many({"item_number": 5}, {"$inc": {"stock": 20}}) # Cambiando el valor de un campo col.update_one({"item_number": 5}, {"$set": {"stock": 0}}) # Añadiendo un valor a un array col.update_one({"item_number": 5}, {"$push": {"tag": "sweet"}}) # Borrando un valor de un array col.update_many({}, {"$pull": {"tag": "sweet"}}) # Reemplazando un documento (también hay replace_many) col.replace_one({"stock": 13}, {"stock": 0, "tags": ["cool"]})

Slide 31

Slide 31 text

Actualizando datos II # Haciendo un upsert res = col.replace_one({"stock": 13}, {"stock": 0, "tags": ["cool"]}, True) print res.upserted_id # Consulta y actualización atómicas. doc = col.find_one_and_update({}, {"$inc": {"stock": 20}) if doc == None: print "No doc to update!" # Devolviendo el documento nuevo from pymongo import ReturnDocument doc = col.find_one_and_update( {'_id': 'userid'}, {'$inc': {'stock': 1}}, return_document=ReturnDocument.AFTER )

Slide 32

Slide 32 text

Borrando datos # Borrando un elemento col.delete_one({"item_number": 5}) # Borrando muchos elementos col.delete_many({"stock": 0}) # Consulta y borrado atómico doc = col.find_one_and_delete({"item_number": 5})

Slide 33

Slide 33 text

PRÁCTICA #1

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

API REST para una tienda online Gestión del catalógo y su stock Gestión de los carritos

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

Esquema para los productos I { "type": "videogame", #obligatorio "title": "The Witness", #obligatorio "stock": 1200, #obligatorio "price": 36.90, #obligatorio "platforms": ["PS4", "PC"], "minimum_requirements": { "ram": "8GB", "cpi": "i7 3.5Ghz", "hd": "40GB" } }

Slide 39

Slide 39 text

Esquema para los productos II { "type": "book", #obligatorio "title": "House of Leaves", #obligatorio "stock": 850, #obligatorio "price": 22.85, #obligatorio "author": "Mark Z. Danielewski", "pages": 736, "isbn": "9780375410345", "book_type": "hardcover" }

Slide 40

Slide 40 text

Esquema para los carros { "session": "__SESSION_ID_039210321", #obligatorio "status": "active", #auto generado "products": [ # documento embebido { "_id": "832013821083210", #obligatorio "quantity": 1, #obligatorio "title": "Sukkwan Island" }, { "_id": "123421432809843", #obligatorio "quantity": 2, #obligatorio "title": "The Grapes of Wrath" } ] }

Slide 41

Slide 41 text

Gestión del catálogo  [GET] /catalog Obtiene todos los productos del catálogo.  [GET] /catalog?type= Obtiene todos los productos del catálogo de un tipo.  [GET] /catalog/ Obtiene un producto.  [PUT] /catalog Añade un producto.  [POST] /catalog/ Edita (reemplaza) los datos de un producto.  [DELETE] /catalog/ Borra un producto.

Slide 42

Slide 42 text

Gestión de los carritos I  [GET] /cart Obtiene todos los carros.  [GET] /cart/ Obtiene un carro.  [PUT] /cart Añade un carro.  [POST] /cart/ Edita (reemplaza) los datos de un carro.  [DELETE] /catalog/ Borra un carro.

Slide 43

Slide 43 text

Gestión de los carros II  [PUT] /cart//product Añade un producto al carros.  [DELETE] /cart/ Borra un producto de un carros. BOLA EXTRA  [GET] /platform/ Devuelve las consolas disponibles y el número de juegos disponibles.

Slide 44

Slide 44 text

A tener en cuenta  Al añadir un producto a un carro hay que actualizar el stock.  Al borrar un producto de un carro hay que actualizar el stock.  Al borrar/actualizar un producto hay que borrarlo de los carros.  Al añadir/editar algo hay que devolver el objeto añadido/modificado.  El código debe ser lo más atómico posible.  ¡Usad índices!

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

Plantilla $ sudo apt-get install git python-dev python-pip $ sudo pip install pymongo Flask $ git clone https://github.com/csuarez/juc-mongodb-api- template.git $ cd juc-mongodb-api-template $ mongoimport --db shop --collection catalog --file catalog.json --host 0.0.0.0 $ python api.py @app.route('/catalog/', methods=['GET']) def catalog_get_single(id): product = catalog_col.find_one({'_id': ObjectId(id)}) if product == None: abort(404) return jsonify(product) Ejemplo https://github.com/csuarez/juc-mongodb-api-template

Slide 47

Slide 47 text

No content