Blog
Como hacer paso a paso una API RESTFUL en Flask con Python
- Publicado por: Rafael Fernandez
- Categoría: API RESTful Blog

Entender como funciona un sistema REST en Flask con una base datos.
Las APIs RESTful están prácticamente en todas partes, su popularidad ha aumentado tanto que es casi imposible pensar que algún proyecto no las implemente. Twitter, Facebook y Youtube son algunas de las empresas que generan negocio gracias a ellas.
Hoy queremos introducirte en el mundo de las APIs si aún no lo has hecho. Existen muchas razones para aprender a desarrollarlas. Son el método estándar para exponer las bases de datos a los clientes.
Ahora bien, el desarrollo de una API en Python es una tarea relativamente fácil. Este paso a paso te ayudará a crear tu propia API RESTful básica en Python con Flask. Sin duda, es un conocimiento que te ayudará a mostrarte ante la industria.
¿Qué es una API REST y cual es su ROL?
Para recordar, las siglas API provienen del término inglés Application Programming Interface o Interfaz de Programación de Aplicaciones. Agrupa al conjunto de reglas, códigos y especificaciones que las aplicaciones deben seguir para que otro software las consuma y se comuniquen entre ellos.
Por otra parte, REST (Representational State Transfer o Transferencia de Estado Representacional) es un estilo arquitectónico y enfoque de comunicaciones utilizado en el desarrollo de servicios web. Fue definido por Roy Fielding y desde el 2000 ha cambiado la ingeniería de software.
Entendiendo mejor, REST es cualquier interfaz entre sistemas que use HTTP para el transporte de datos haciendo uso también de los métodos de este protocolo para comunicarse (GET, POST, PUT, PATCH y DELETE). Permite trabajar con múltiples formatos de datos como XML, JSON, datos binarios y texto plano. Esto hace tomar ventaja a este enfoque, pues en el caso de SOAP (Simple Object Access Protocol) solo admite el formato XML.
Se considera a una API de tipo REST cuando su arquitectura se ajusta a las reglas y restricciones de esta interfaz. La verdad es que en el campo de las APIs, REST se ha vuelto el estándar más lógico, flexible, eficiente y habitual. En esta ocasión nos centraremos en la construcción de una API de este tipo.
¿Qué es Flask?
Se trata de un micro framework completo, rápido y ligero. Con él se desarrollan aplicaciones web y APIs de forma sencilla, utilizando Python como lenguaje de programación.
Entre las características de Flask destacan que tiene un ecosistema desacoplado de componentes, el núcleo es muy pequeño y permite al programador tomar decisiones en cuanto a la arquitectura. Adicionalmente, brinda el potencial de instalar las extensiones o complementos que en realidad vas a utilizar, de acuerdo al tipo de proyecto que desarrolles.
No incluye un Object-Relational mapping (ORM), adaptador de bases de datos ni sistemas de login. El programador es quien se encarga de esas decisiones de diseño. Incluye servidor web de desarrollo, depurador y soporte para pruebas unitarias, su gestión de rutas es eficiente y muchas más ventajas de las que puedes sacar provecho.
En esta ocasión empezaremos con lo básico, construir una API Rest con Flask y a partir de aquí construirás sistemas completos.
¿Qué necesitamos para construir una API básica en Python con Flask?
Para poder desarrollar el API de manera correcta deberás instalar los siguientes requisitos.
- Python
- Flask
- Flask-SQLAlchemy
- Flask-Restful
- SQlite3
- Jsonify
También es recomendado que tengas algún editor, algunas opciones son Sublime Text o PyCharm o Anaconda. Por último, tus ganas e interés por aprender no se pueden quedar atrás.
Configuración y preparación del entorno
Base de datos:
Para hacer un poco rápido el proceso, descarga el ejemplo de base de datos de SQLite haciendo click chinook.
Esta base datos tiene bastantes campos, como tracks (pistas) donde podemos encontrar json de nombres de autor, nombre de la canción, trackID, precios… todo esto en la ruta http://127.0.0.1:5000/tracks. También podemos encontrar otros tipos de datos de empleados dodne podemos encontrar json con campos sobre nacimiento, nombre, ciudad, email … todo esto en la ruta 127.0.0.1:5000/employees/
La base datos viene en un archivo .zip, extráelo en la carpeta del proyecto a la que llamaremos API-REST-tutorial.
Una vez que lo descargues, crea un archivo llamado apiejemplo2.py en la carpeta del proyecto. Este archivo contendrá las definiciones de la API y el código de Flask.
Entorno Virtual:
Ahora, creamos un entorno virtual básico para Python 3.6 e instalamos los paquetes después de su activación. Se utiliza virtualenv, en caso de no tenerlo instalado, ejecuta este comando:
sudo apt-get install python-virtualenv
El entorno virtual permite aislar la aplicación junto con sus dependencias de otras aplicaciones Python que existan dentro de nuestro sistema. De esta manera se evita que las librerías de cada aplicación entren en conflicto.
Luego de aclarar esto, procedemos a inicializar el entorno Python. Entramos en el terminal, nos situamos dentro de la carpeta del proyecto <API-REST-tutorial> y ejecutamos el siguiente comando:
virtualenv env
Una vez que hemos creado nuestro entorno, debemos indicarle al terminal que queremos hacer uso del mismo y no del entorno Python global del sistema. Por tanto ejecuta:
source env/bin/activate
Sabremos que ya el entorno se encuentra activo porque el prompt empieza con “(env)” como se observa en la imagen:
Si quieres más info sobre entornos virtuales puedes ir a este post donde se explica con mas profundidad.
Instalación de Flask y demás requisitos
Escribe en el terminal el siguiente comando:
pip install flask flask-jsonpify flask-sqlalchemy flask-restful
De esta forma, se instalarán dentro del entorno “(env)” el framework y las dependencias con las que trabajaremos.
Si quieres asegurarte que todas las dependencias de la aplicación estén instaladas, ejecuta el siguiente comando:
pip freeze
Hasta ahora tenemos todo listo para crear nuestra API RESTful básica en Python con Flask, empecemos con el código
Métodos HTTP
Como REST trabaja con el protocolo HTTP, ofrece 4 opciones para manipulación de datos:
- GET : Para hacer consultas y obtener un recurso
- POST : Para crear un recurso
- PUT: Para modificar un recurso
- DELETE: Para eliminar un recurso
Empezamos con GET. Pero antes, conéctate a la base de datos con el siguiente comando:
sqlite3 chinook.db
Para salir de sqlite solo tienes pulsar contro + C.
En primer lugar obtendremos la data de todos los empleados y las pistas (employees and tracks). Luego agregaremos un operador de consulta para obtener los datos de un empleado específico.
from flask import Flask, request, jsonify from flask_restful import Resource, Api from sqlalchemy import create_engine db_connect = create_engine('sqlite:////chinook.db') #La ruta depende de donde tengas almacenada la base de datos app = Flask(__name__) api = Api(app) class Employees(Resource): def get(self): conn = db_connect.connect() # Conexión a la Base de Datos query = conn.execute("select * from employees") # Esta línea ejecuta un query y retorna un json como resultado return {'employees': [i[0] for i in query.cursor.fetchall()]} # Se obtiene la primera columna que es EmployeeId def post(self): conn = db_connect.connect() last_name = request.json['LastName'] first_name = request.json['FirstName'] title = request.json['Title'] reports_to = request.json['ReportsTo'] birth_date = request.json['BirthDate'] hire_date = request.json['HireDate'] address = request.json['Address'] city = request.json['City'] state = request.json['State'] country = request.json['Country'] postal_code = request.json['PostalCode'] phone = request.json['Phone'] fax = request.json['Fax'] email = request.json['Email'] query = conn.execute("insert into employees values(null,'{0}','{1}','{2}','{3}', \ '{4}','{5}','{6}','{7}','{8}','{9}','{10}','{11}','{12}', \ '{13}')".format(last_name,first_name,title, reports_to, birth_date, hire_date, address, city, state, country, postal_code, phone, fax, email)) return {'status': 'Nuevo empleado añadido'} class Tracks(Resource): def get(self): conn = db_connect.connect() query = conn.execute("select trackid, name, composer, unitprice from tracks;") result = {'data': [dict(zip(tuple (query.keys()), i)) for i in query.cursor]} return jsonify(result) class EmployeeData(Resource): def get(self, employee_id): conn = db_connect.connect() query = conn.execute("select * from employees where EmployeeId =%d " % int(employee_id)) result = {'data': [dict(zip(tuple(query.keys()), i)) for i in query.cursor]} return jsonify(result) api.add_resource(Employees, '/employees') # Route_1 api.add_resource(Tracks, '/tracks') # Route_2 api.add_resource(EmployeeData, '/employees/<employee_id>') # Route_3 if __name__ == '__main__': app.run(port='5000')
Al tener el código listo, ejecuta el proyecto, Cuando lo ejecutas deberás ver por la consa algo así:
* Serving Flask app "apimj" (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Para ver cuantos usuarios están registrados ingresa la ruta http://127.0.0.1:5000/employees en cualquier navegador:
Para visualizar todas las pistas registradas, ingresa la ruta 2
Por último, para una búsqueda específica ingresa la ruta 3 colocando el id de un empleado.
Ahora vamos hacer peticiones con Postman [GET, POST, PULL y DELETE]
GET
¿Cuántos empleados tenemos en nuestra base de datos?
Para ello hacemos un peticion GET dentro de la clase Employees a la función get a la ruta http://127.0.0.1:5000/employees y hacemos click en send. Como vemos en la imagen aparecen 8 empleados:
POST
Si te fijas en el código, para realizar el POST hemos implementado una función dentro de clase de Employees, esta función está esperando una serie de campos que si se los damos nos introduce un nuevo empleado en nuestra base de datos. Vamos a introducir un nuevo empleado con el siguiente json:
{ "LastName" :"Fernadez", "FirstName" : "Manuel", "Title" : "IT", "ReportsTo" : "John", "BirthDate" : "3/6/19", "HireDate" : "3/5/11", "Address" : "mesa 4", "City" : "Barcelona", "State" : "Spain", "Country" : "españa", "PostalCode" : "45889", "Phone" : "457823667", "Fax" : "5454545454", "Email" : "fermanu2@gmail.com" }
Hacemos el POST con nuestro json:
En esta ocasión, para comprobar que se haga el registro de un nuevo empleado haremos uso de Postman. Colocas el tipo de petición (POST), la ruta http://127.0.0.1:5000/employees y el JSON que vas a enviar. Haces click en Send. Si es exitoso el API te devuelve “status”: ” Nuevo empleado añadido” como puedes observar en la imagen de arriba.
GET
Comprobamos de nuevo que el nuevo empleado ha sido añadido y lo podemos hacer de dos formas:
- GET en esta ruta http://127.0.0.1:5000/employeesGet y comprobar que tenemos 9 empleados
- GET en esta ruta http://127.0.0.1:5000/employees/9 y comprobar los datos propios del empleado, hacemos esta y la añadimos en la siguiente imagen:
PUT
¿Que pasa si me he equivocado en uno de los campos? El empleado se llama ManuelJavier y no Manuel, para ello tenemos el método PUT.
Seguimos ahora con el PUT, para el cual definimos una clase llamada UpdateEmployee en la cual se modifica el FirstName. A continuación el código.
class UpdateEmployee(Resource): def put(self, employee_id): first_name = request.json['FirstName'] conn = db_connect.connect() query = conn.execute("update employees set FirstName='%s' where EmployeeId=%s" % (first_name, int(employee_id))) return {'status':'Cambio de nombre realizado'}
Y agregas la ruta
api.add_resource(UpdateEmployee, '/employee/<employee_id>') # Route_4
De igual forma, para probar hacemos uso de Postman. Colocamos la ruta con el id del employee que queramos modificar, PUT como método y enviamos un JSON en este caso con el FirstName. Por ejemplo:
Ahora hacemos un GET para comprobar y vemos efectivamente que el nombre ha sido actualizado en la siguiente imagen:
DELETE
Finalmente, para borrar algún empleado de la base de datos procedemos con un DELETE. La clase en este caso es DeleteEmployee, recibe el id como parametro. El código es:
class DeleteEmployee(Resource): def delete(self, employee_id): conn = db_connect.connect() query = conn.execute("delete from employees where EmployeeId=%d " % int(employee_id)) return {'status':'Empleado borrado con éxito'}
Y la ruta:
api.add_resource(DeleteEmployee, '/delete/<employee_id>') # Route_5
Haciendo uso de postman, haz la petición a la ruta
Para asegurarte, realiza la petición GET y verifica que ya no se encuentre el usuario eliminado.
Aquí tienes el código completo para hacer tus pruebas y entender un sistema de API REST con una base datos sqlite
from flask import Flask, request, jsonify from flask_restful import Resource, Api from sqlalchemy import create_engine db_connect = create_engine('sqlite:///chinook.db') #La ruta depende de donde tengas almacenada la base de datos app = Flask(__name__) api = Api(app) class Employees(Resource): def get(self): conn = db_connect.connect() # Conexión a la Base de Datos query = conn.execute("select * from employees") # Esta línea ejecuta un query y retorna un json como resultado return {'employees': [i[0] for i in query.cursor.fetchall()]} # Se obtiene la primera columna que es EmployeeId def post(self): conn = db_connect.connect() last_name = request.json['LastName'] first_name = request.json['FirstName'] title = request.json['Title'] reports_to = request.json['ReportsTo'] birth_date = request.json['BirthDate'] hire_date = request.json['HireDate'] address = request.json['Address'] city = request.json['City'] state = request.json['State'] country = request.json['Country'] postal_code = request.json['PostalCode'] phone = request.json['Phone'] fax = request.json['Fax'] email = request.json['Email'] query = conn.execute("insert into employees values(null,'{0}','{1}','{2}','{3}', \ '{4}','{5}','{6}','{7}','{8}','{9}','{10}','{11}','{12}', \ '{13}')".format(last_name,first_name,title, reports_to, birth_date, hire_date, address, city, state, country, postal_code, phone, fax, email)) return {'status': 'Nuevo empleado añadido'} class Tracks(Resource): def get(self): conn = db_connect.connect() query = conn.execute("select trackid, name, composer, unitprice from tracks;") result = {'data': [dict(zip(tuple (query.keys()), i)) for i in query.cursor]} return jsonify(result) class EmployeeData(Resource): def get(self, employee_id): conn = db_connect.connect() query = conn.execute("select * from employees where EmployeeId =%d " % int(employee_id)) result = {'data': [dict(zip(tuple(query.keys()), i)) for i in query.cursor]} return jsonify(result) class UpdateEmployee(Resource): def put(self, employee_id): first_name = request.json['FirstName'] conn = db_connect.connect() query = conn.execute("update employees set FirstName='%s' where EmployeeId=%s" % (first_name, int(employee_id))) return {'status':'Cambio de nombre realizado'} class DeleteEmployee(Resource): def delete(self, employee_id): conn = db_connect.connect() query = conn.execute("delete from employees where EmployeeId=%d " % int(employee_id)) return {'status':'Empleado borrado con éxito'} api.add_resource(Employees, '/employees') # Route_1 api.add_resource(Tracks, '/tracks') # Route_2 api.add_resource(EmployeeData, '/employees/<employee_id>') # Route_3 api.add_resource(UpdateEmployee, '/employee/<employee_id>') # Route_4 api.add_resource(DeleteEmployee, '/delete/<employee_id>') # Route_5 if __name__ == '__main__': app.run(port='5000')
➡ Esperamos que hayas puesto en práctica varios de los conceptos estudiados. Continúa aprendiendo con nuestro curso de creación de APIs RESTful con Flask – Python:
cómo se ejecuta el proyecto?
Hola Gerson, si usas spyder puedes ejecutarlos con el boton de run. Si lo ejecutas por la terminal nombra a tu archivo como app.py previamente y ejecuta el comando: python app.py , saludos!
Explicado a la perfección, fácil de entender lo probé y funciono de 10 muchísimas gracias por compartir tus conocimientos.
hice todo, no me da errores al compliar, la db de sqlite3 la puse a la altura de apiejemplo2.py “db_connect = create_engine(‘sqlite:////chinook.db’)” y me dice esto la pagina {“message”: “Internal Server Error”}
Que tal Geek tengo el mismo problema, tu pudiste solucionarlo?
El problema es en la ruta, debe ir así: (‘sqlite:///chinook.db’), solo con 3 barras inclinadas.
A mi cuando hago el POST para ingresar un nuevo employee me dice internal server error.
Hola Brooan, si te sale ese error revisa bien los códigos ya que indica que falta algo.
Era un problema con el Json todo correcto. Gracias.
Hola, podrías describir como solucionaste el problema??
Cómo puedo dejar ya el ambiente virtual corriendo siempre
Hola Gilberto, revisa este post para la gestion de ambientes virtuales https://unipython.com/entornos-virtuales-en-python-y-anaconda/
algún servidor que me recomienden para subir esta api ??
Hola Rodrigo, no recomendamos ninguno ya que es un ejercicio y solemos usar siempre localhost.