Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Construyendo una API REST con Python y MongoDB

Construyendo una API REST con Python y MongoDB

Avatar for César Suárez Ortega

César Suárez Ortega

February 11, 2016
Tweet

More Decks by César Suárez Ortega

Other Decks in Programming

Transcript

  1. CONSTRUYENDO UNA API REST CON PYTHON Y MONGODB César Suárez

    Ortega <[email protected]> II Jornadas Técnicas UEx – CIEMAT: Introducción a NoSQL con MongoDB 9 – 11 de Febrero, 2016
  2. Índice Qué es una API REST  Python + MongoDB =

    PyMongo Práctica: API para una tienda online
  3. 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
  4. 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.
  5. 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.
  6. 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/
  7. 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)" } ] }
  8. 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
  9. 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)
  10. 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} )
  11. 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']
  12. 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'): ...
  13. 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']} ])
  14. 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 } ]
  15. 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']
  16. 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"]})
  17. 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 )
  18. 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})
  19. 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" } }
  20. 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" }
  21. 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" } ] }
  22. Gestión del catálogo  [GET] /catalog Obtiene todos los productos del

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

    carros.  [GET] /cart/<objectid> Obtiene un carro.  [PUT] /cart Añade un carro.  [POST] /cart/<objectid> Edita (reemplaza) los datos de un carro.  [DELETE] /catalog/<objectid> Borra un carro.
  24. Gestión de los carros II  [PUT] /cart/<cart_id>/product Añade un producto

    al carros.  [DELETE] /cart/<objectid> Borra un producto de un carros. BOLA EXTRA  [GET] /platform/ Devuelve las consolas disponibles y el número de juegos disponibles.
  25. 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!
  26. 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/<id>', 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