API Rest Ful con Flask y MongoDB (Flask-MongoAlchemy)
En artículo anterior se hizo un CRUD para Flask con MongoDB usando Mongo-Alchemy, en dicho artículo se manejaron varios URL para hacer el CRUD.En este artículo se manejará el REST por medio de los URL y con Flask solamente, en próximos artículos se usará Flask-RESTful y Flask-Restless.
Métodos de HTTP
En este caso se va a estandarizar el CRUD por medio de API Rest Ful, donde se usará el mismo URL con métodos GET, POST, PUT y DELETE.Los métodos se usarán de la siguiente forma:
- Agregar Empleado: Método POST, URL /empleado, sin parámetros.
- Buscar Empleado: Método GET, URL /empleado, parámetro <string:nombre>.
Empleados: Método GET, URL /Listar .empleado - Editar/Actualizar Empleado: Método PUT, URL /empleado, parámetro <string:nombre>.
- Borrar Empleado: Método DELETE, URL /empleado, parámetro <string:nombre>.
Como puede notarse, con un sólo URL se tiene las acciones del CRUD usando los métodos de HTTP, esto permite estándarizar y simplificar el uso de los URL, y principalmente hacer un correcto uso de HTTP:
Para más información sobre el estilo arquitectónico API REST pueden revisar en wikipedia.
Estructura de directorios y archivos
Se mantiene la misma estructura de archivos y directorios del artículo sobre CRUD:
├── app
│ └── run. py
├── docker-compose. yml
├── Dockerfile
└── README. md
Archivo Dockerfile y docker-compose. yml
FROM python
WORKDIR /code/
RUN pip3 install --upgrade pip
RUN pip3 install
pymongo RUN pip3 install Flask
RUN pip3 install Flask-PyMongo
RUN pip3 install Flask-MongoAlchemy
EXPOSE 5000
ADD
/ . /* /code/ app COPY
/ . /* /code/ app CMD python
run . py
flask -rest1:
build : .
ports :
- "5000:5000"
volumes :
- ". /app /: /code"
links :
- mongo
mongo :
image : mongo
ports :
- "27017:27017"
volumes :
- "/srv /data/db : /data/db : rw "
Codigo de la aplicación
El código de run.py se muestra a continuación:
#
/usr/bin/env python !
#SeFlask, importa reqest y jsonify flask import Flask, request from , jsonify #SeMongoAlchemy importa flask_mongoalchemy import MongoAlchemy from #Sedumps importa from bson json_util import dumps . #Se instancia la clase de Flask, se configura el acceso#a la base de datosa mongodb empleados = Flask app __name__) ( app config . 'MONGOALCHEMY_DATABASE'] = ' [ ' empleados app config . 'MONGOALCHEMY_CONNECTION_STRING'] = ' [ mongodb // : mongo 27017/ : ' empleados #Se instancia mongoalchemy pasando la app.= MongoAlchemy db app) ( #Se crea la clase empleados la cual manejara los documentos.class empleados ( db Document): . = nombre db StringField . ) ( = sexo db StringField . ) ( = edad db IntField . ) ( = dni db IntField . ) ( #Se define lafuncion con agregar get metodo @approute . '/ ( ' empleado methods= , 'POST']) [ def agregar ): ( #Se crea la instancia empleado de la clase empleados donde se#logra hacer la inserción de un empleado con el metodo save.= nombre str request ( . json ' [ ']) nombre = sexo str request ( . json ' [ ']) sexo = edad int request ( . json ' [ ']) edad = dni int request ( . json ' [ ']) dni empleado = empleados(nombre=nombre,sexo=sexo,edad=edad,dni=dni)empleado save . ) ( #Se retorna que el usuario fue agregado.###= consulta empleados query . all . ) ( = [] listado for in i : consulta listado append . ( wrap i. )) ( dumps return ( ) listado #Se crea la funcion buscar con metodo get.@approute . '/ ( /<string empleado : >' nombre methods= , 'GET']) [ def buscar ( ): nombre #Se realiza la busqueda y se devuelve el resultado, si existe un error de atributo (que el empleado no existe)#Sedevuelve no empleado . encontrado : try = resultado empleados query . filter . ( empleados . == nombre ) nombre first . ) ( dumps return {' ( ' resultado {' : ' nombre : resultado . ,' nombre ' sexo : resultado . ,' sexo ' edad : resultado . ,' edad ' dni : resultado . }}) dni (AttributeError): except dumps return {' ( ': 'Empleado no resultado '}) encontrado @approute . '/ ( ' empleado methods= , 'GET']) [ def listar ): ( #Se realiza la busqueda y se devuelve el resultado, si existe un error de atributo (que el empleado no existe)#Sedevuelve no empleado . encontrado : try = consulta empleados query . all . ) ( = [] resultado for in i : consulta resultado append . ( wrap i. )) ( dumps return ( ) resultado (AttributeError): except dumps return {' ( ': 'Empleado no resultado '}) encontrado #Se crea la funcion actualizar que tiene metodo put, con#url /empleado y se le pasa el nombre a buscar@approute . '/ ( /<string empleado : >' nombre methods= , 'PUT']) [ def actualizar ( ): nombre #Se intenta buscar al empleado en la base de datos, si no esta devuelve error: try #Se consulta en la base de datos, donde devuelve el primer elemento encontrado= resultado empleados query . filter . ( empleados . == nombre ) nombre first . ) ( #Se toma los datos de un json y se guardan en sus variables, salvando luego#en la base de datos.resultado . = sexo str request ( . json ' [ ']) sexo resulado . = edad int request ( . json ' [ ']) edad resultado . = dni int request ( . json ' [ ']) dni resultado save . ) ( #Se realiza la consulta desplegando los empleados= consulta empleados query . all . ) ( = [] listado for in i : consulta listado append . ( wrap i. )) ( #Se devuelve la nueva lista de empleados en un json.dumps return ( ) listado (AttributeError): except dumps return {' ( ': 'Empleado no resultado '}) encontrado #Borrar un empleado de la base de datos, se pasa el url /empleado con el#stringnombre el usando delete. metodo @approute . '/ ( /<string empleado : >' nombre methods= , 'DELETE']) [ def borrar ( ): nombre #Se busca el empleado, si existe se borra de la base de datos y se devuelve#mensaje de empleado borrado, si no, se devuelve el mensaje de empleado no#encontrado.: try = resultado empleados query . filter . ( empleados . == nombre ) nombre first . ) ( resultado remove . ) ( ###= consulta empleados query . all . ) ( = [] listado for in i : consulta listado append . ( wrap i. )) ( dumps return ( ) listado (AttributeError): except dumps return {' ( ':'Empleado no resultado '}) encontrado __nam if e__ == "__mai n__":#Se corre la aplicacion en modo debugapp . run host="0.0.0.0" ( debug=True) ,
Construcción de la imagen y ejecución del contenedor
Construcción de la imagen Docker:
Ejecución del contenedor :
Pruebas del API REST FUL
Para este caso se usará POSTMAN, una aplicación para google chrome.
Listar Empleados
Se usa postman colocando 127.0.0.1:5000/empleados con método GET, en la siguiente figura se muestra el listado:
El JSON que devuelve es el siguiente:
[{"edad": 29, "dni": 8, "sexo": "Femenino", "nombre": "Jane Doe", "_id": {"$oid": "57ebbce45fd2bbeffc51330b"}}, {"edad": 39, "dni": 7, "sexo": "Masculino", "nombre": "John Doe", "_id": {"$oid": "57ebbd195fd2bbeffc51330c"}}, {"edad": 55, "dni": 6, "sexo": "Masculino", "nombre": "Pedro Perez", "_id": {"$oid": "57ebbd505fd2bbeffc51330d"}}, {"edad": 65, "dni": 5, "sexo": "Femenino", "nombre": "Petra", "_id": {"$oid": "57ebbd6b5fd2bbeffc51330e"}}, {"edad": 18, "dni": 4, "sexo": "Masculino", "nombre": "Luis Gonzalez", "_id": {"$oid": "57ebc34d5fd2bbeffc51330f"}}, {"edad": 34, "dni": 2, "sexo": "Femenino", "nombre": "Luissana", "_id": {"$oid": "57ebc3935fd2bbeffc513311"}}, {"edad": 43, "dni": 1, "sexo": "Masculino", "nombre": "Neg", "_id": {"$oid": "57ebc4b85fd2bbeffc513312"}}, {"edad": 29, "dni": 1050, "sexo": "Femenino", "nombre": "Dayana", "_id": {"$oid": "57f64d7d557e3f00086651e8"}}]
Buscar un Empleado
En el postman se coloca el siguiente url con método GET 127.0.0.1/empleado/Neg , la siguiente figura muestra el resultado:
EL JSON que devuelve es el siguiente:
{"resultado": {"edad": 43, "dni": 1, "sexo": "Masculino", "nombre": "Neg"}}
Agregar Empleado
En postman se agrega el url con método POST 127.0.0.1:5000/empleado y se pasa en formato JSON lo siguiente:
{
"nombre ": "Fatima",
"sexo ": "Femenino",
"edad ": 24,
"dni ": 1052
}
La siguiente figura muestra la captura de la información que se coloca en postman:
Esto devuelve el siguiente JSON:
[{"edad": 29, "dni": 8, "sexo": "Femenino", "nombre": "Jane Doe", "_id": {"$oid": "57ebbce45fd2bbeffc51330b"}}, {"edad": 39, "dni": 7, "sexo": "Masculino", "nombre": "John Doe", "_id": {"$oid": "57ebbd195fd2bbeffc51330c"}}, {"edad": 55, "dni": 6, "sexo": "Masculino", "nombre": "Pedro Perez", "_id": {"$oid": "57ebbd505fd2bbeffc51330d"}}, {"edad": 65, "dni": 5, "sexo": "Femenino", "nombre": "Petra", "_id": {"$oid": "57ebbd6b5fd2bbeffc51330e"}}, {"edad": 18, "dni": 4, "sexo": "Masculino", "nombre": "Luis Gonzalez", "_id": {"$oid": "57ebc34d5fd2bbeffc51330f"}}, {"edad": 34, "dni": 2, "sexo": "Femenino", "nombre": "Luissana", "_id": {"$oid": "57ebc3935fd2bbeffc513311"}}, {"edad": 43, "dni": 1, "sexo": "Masculino", "nombre": "Neg", "_id": {"$oid": "57ebc4b85fd2bbeffc513312"}}, {"edad": 29, "dni": 1050, "sexo": "Femenino", "nombre": "Dayana", "_id": {"$oid": "57f64d7d557e3f00086651e8"}}, {"edad": 24, "dni": 1052, "sexo": "Femenino", "nombre": "Fatima", "_id": {"$oid": "57f68505557e3f000e1aa766"}}]
Como se nota el empleado Fátima aparece en la base de datos al final.
Borrar Empleado
Para este caso se buscará borrar al empleado Fátima, se coloca el siguiente url en postman con método DELETE: 127.0.0.1:5000/empleado/Fatima .
La siguiente imagen muestra la ejecución en postman:
Esto devuelve el siguiente JSON:
[{"edad": 29, "dni": 8, "sexo": "Femenino", "nombre": "Jane Doe", "_id": {"$oid": "57ebbce45fd2bbeffc51330b"}}, {"edad": 39, "dni": 7, "sexo": "Masculino", "nombre": "John Doe", "_id": {"$oid": "57ebbd195fd2bbeffc51330c"}}, {"edad": 55, "dni": 6, "sexo": "Masculino", "nombre": "Pedro Perez", "_id": {"$oid": "57ebbd505fd2bbeffc51330d"}}, {"edad": 65, "dni": 5, "sexo": "Femenino", "nombre": "Petra", "_id": {"$oid": "57ebbd6b5fd2bbeffc51330e"}}, {"edad": 18, "dni": 4, "sexo": "Masculino", "nombre": "Luis Gonzalez", "_id": {"$oid": "57ebc34d5fd2bbeffc51330f"}}, {"edad": 34, "dni": 2, "sexo": "Femenino", "nombre": "Luissana", "_id": {"$oid": "57ebc3935fd2bbeffc513311"}}, {"edad": 43, "dni": 1, "sexo": "Masculino", "nombre": "Neg", "_id": {"$oid": "57ebc4b85fd2bbeffc513312"}}, {"edad": 29, "dni": 1050, "sexo": "Femenino", "nombre": "Dayana", "_id": {"$oid": "57f64d7d557e3f00086651e8"}}]
Modificar empleado
Para este caso se modificará el empleado Neg, cambiando su edad.
Se abre el postman colocando el url 127.0.0.1:5000/empleado/Neg con método PUT. Adicional se agrega el JSON:
{
"sexo ": "Masculino",
"edad ": 41,
"dni ": 1
}
La siguiente imagen muestra el postman:
Esto devuelve el siguiente JSON:
[{"sexo": "Femenino", "_id": {"$oid": "57ebbce45fd2bbeffc51330b"}, "nombre": "Jane Doe", "dni": 8, "edad": 29}, {"sexo": "Masculino", "_id": {"$oid": "57ebbd195fd2bbeffc51330c"}, "nombre": "John Doe", "dni": 7, "edad": 39}, {"sexo": "Masculino", "_id": {"$oid": "57ebbd505fd2bbeffc51330d"}, "nombre": "Pedro Perez", "dni": 6, "edad": 55}, {"sexo": "Femenino", "_id": {"$oid": "57ebbd6b5fd2bbeffc51330e"}, "nombre": "Petra", "dni": 5, "edad": 65}, {"sexo": "Masculino", "_id": {"$oid": "57ebc34d5fd2bbeffc51330f"}, "nombre": "Luis Gonzalez", "dni": 4, "edad": 18}, {"sexo": "Femenino", "_id": {"$oid": "57ebc3935fd2bbeffc513311"}, "nombre": "Luissana", "dni": 2, "edad": 34}, {"sexo": "Masculino", "_id": {"$oid": "57ebc4b85fd2bbeffc513312"}, "nombre": "Neg", "dni": 1, "edad": 41}, {"sexo": "Femenino", "_id": {"$oid": "57f64d7d557e3f00086651e8"}, "nombre": "Dayana", "dni": 1050, "edad": 29}]
Se muestra en subrayado el empleado Neg que cambió su edad en la base de datos.
Para terminar, ahora se muestra la salida del servidor:
flask-rest1_1 | 172.17.0.1 - - [06/Oct/2016 15:59:33] "GET /empleado HTTP/1.1" 200 -
flask-rest1_1 | 172.17.0.1 - - [06/Oct/2016 16:03:48] "GET /empleado /Neg HTTP/1.1" 200 -
flask-rest1_1 | 172.17.0.1 - - [06/Oct/2016 17:08:22] "POST /empleado HTTP/1.1" 200 -
flask-rest1_1 | 172.17.0.1 - - [06/Oct/2016 17:39:24] "DELETE /empleado /Fatima HTTP/1.1" 200 -
flask-rest1_1 | 172.17.0.1 - - [06/Oct/2016 17:47:59] "PUT /empleado /Neg HTTP/1.1" 200 -
Como se ve, la salida devuelve el URL que se usa y los métodos utilizados.
De esta manera se muestra el uso del estilo arquitectónico API REST y el uso de HTTP con sus diferentes métodos.
El código fuente de este artículo se encuentra en el repositorio tutorial-flask de gitlab en la rama mongo-restful.
No hay comentarios:
Publicar un comentario