Pro Yearly is on sale from $80 to $50! »

JUC2016 - Hands-on lab: Construyendo una API REST con Python y MongoDB

C4187f9cd1f03aa1619b269218883910?s=47 CETA-Ciemat
February 11, 2016

JUC2016 - Hands-on lab: Construyendo una API REST con Python y MongoDB

II Jornadas Técnicas UEx – CIEMAT. Hands-on lab: Construyendo una API Rest con MongoDB y Python

C4187f9cd1f03aa1619b269218883910?s=128

CETA-Ciemat

February 11, 2016
Tweet

Transcript

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

    Ortega <cesar.suarez@externos.ceta-ciemat.es> II Jornadas Técnicas UEx – CIEMAT: Introducción a NoSQL con MongoDB 9 – 11 de Febrero, 2016
  2. None
  3. None
  4. Software Developer / Researcher César Suárez Ortega tharandur csuarez

  5. Software Developer / Researcher César Suárez Ortega

  6. POWERED BY

  7. Software Developer / Researcher César Suárez Ortega

  8. Índice Qué es una API REST  Python + MongoDB =

    PyMongo Práctica: API para una tienda online
  9. APIs REST

  10. None
  11. 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
  12. 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.
  13. 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.
  14. ¿Por qué REST?

  15. None
  16. http://getpostman.com

  17. PyMongo

  18. Python

  19. 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/
  20. http://bit.ly/juc-pymongo-code

  21. 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)" } ] }
  22. 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
  23. 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)
  24. 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} )
  25. 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']
  26. 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'): ...
  27. 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']} ])
  28. 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 } ]
  29. 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']
  30. 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"]})
  31. 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 )
  32. 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})
  33. PRÁCTICA #1

  34. None
  35. None
  36. API REST para una tienda online Gestión del catalógo y

    su stock Gestión de los carritos
  37. None
  38. 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" } }
  39. 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" }
  40. 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" } ] }
  41. 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.
  42. 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.
  43. 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.
  44. 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!
  45. None
  46. 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
  47. None