Crear una Api Restful en Flask con autenticación requerida
Índice de contenido
- Qué es una API RESTful y por qué usar Flask para crearla
- Diferencias entre REST y RESTful
- Preparar el entorno de trabajo: Herramientas necesarias
- Mejores prácticas y conociendo flask restful
- Conversión automática de objeto a diccionario
- Implementando el CRUD completo
- Método POST: crear nuevos recursos
- Método GET: obtener todos los registros
- Métodos PATCH/PUT: actualizar datos
- Método DELETE: eliminar un registro
- Otras funcionalidades
- Puntos a tener en cuenta
- Seguridad y Autenticación requerida en la Restful con Flask
- Conclusión
- Preguntas frecuentes (FAQ)
Crear una Restful API en Flask es una de las formas más simples y efectivas de conectar aplicaciones y sistemas. En mi experiencia, Flask ofrece la flexibilidad ideal para construir servicios web limpios, seguros y fáciles de mantener. A lo largo de esta guía te muestro cómo lo hago paso a paso, desde la instalación hasta la autenticación, incluyendo código real y consejos prácticos que me han funcionado en proyectos reales.
Qué es una API RESTful y por qué usar Flask para crearla
Una API RESTful sigue el principio de que cada recurso del sistema se representa mediante una URL única y se manipula a través de los métodos HTTP estándar:
- GET: obtener información.
- POST: crear nuevos recursos.
- PUT/PATCH: actualizar datos existentes.
- DELETE: eliminar registros.
Una Api Rest es una estructura en base a funciones que son muy empleadas hoy en día para comunicar sistemas o distintas aplicaciones, cada recurso que podemos crear son simplemente funciones que a la final son traducidas mediante URLs que son consumidas vía HTTP y los métodos del mismo:
Por lo tanto, dependiendo del método HTTP nosotros podemos dar una respuesta distinta, siempre respetando el propósito de cada tipo de petición HTTP.
Flask es perfecto para esto porque permite construir una API ligera sin configuración excesiva. Con solo unas líneas de código ya tienes endpoints funcionando, y con el paquete Flask-Restful puedes estructurar todo en clases bien organizadas.
Diferencias entre REST y RESTful
“REST” es el estilo arquitectónico, mientras que “RESTful” se refiere a la implementación práctica que cumple con esos principios: recursos bien definidos, comunicación vía HTTP y formato JSON.
Ventajas de usar Flask frente a otros frameworks
- Ligereza: ideal para microservicios o APIs específicas.
- Extensibilidad: compatible con extensiones como Flask-Restful, Flask-HTTPAuth, SQLAlchemy.
- Curva de aprendizaje corta: se domina rápidamente si ya conoces Python.
Preparar el entorno de trabajo: Herramientas necesarias
Así que, para trabajar con este paquete, lo primero que necesitamos es nuestra aplicación en Flask y luego instalar el paquete para el Restful mediante:
$ pip install flask-restfulEstructura base del proyecto:
my_app/
│
├── app.py
├── models.py
├── rest/
│ ├── controllers.py
│ └── __init__.py
└── auth/
├── model/
│ └── user.pyAhora ya estamos listos para poder emplear este paquete.
Mejores prácticas y conociendo flask restful
La clave para una buena API no es solo que funcione, sino que sea predecible y coherente.
Algunos errores comunes que conviene evitar:
- No validar la entrada del usuario antes de operar con la base de datos.
- No devolver mensajes claros ante errores 400 o 404.
- No documentar los endpoints ni sus parámetros.
Siempre recomiendo probar los endpoints con Postman o CURL y documentar usando Swagger o OpenAPI si la API crecerá.
Conversión automática de objeto a diccionario
Otro elemento muy interesante es que nosotros tenemos un decorador llamado marshal_with que nos permite indicar de una que campos queremos devolver del modelo con el cual estamos trabajando cada vez que retornamos el objeto; para eso primero tenemos que definir la estructura que sostenga lo anteriormente comentado:
resource_fields = {
'id': fields.Integer,
'name' : fields.String
}Este decorador también recibe de manera opcional el envoltorio del json que va a devolver que podemos configurar mediante el envelope.
Implementando el CRUD completo
Cómo funcionan los métodos HTTP
Cada método HTTP tiene un propósito concreto y conviene respetarlo siempre. En mis proyectos, me ha ayudado mucho mantener esta convención porque simplifica el mantenimiento del código y la documentación.
Creación de las clases Resource
Con Flask-Restful, cada clase Resource representa un conjunto de operaciones sobre un recurso.
Me gusta separar las clases que no necesitan un id (para listar o crear) de las que sí lo requieren (para leer, actualizar o borrar).
Vamos a crear un par de clases por cada entidad que queramos hacer gestionables es decir realizar el CRUD sobre algún modelo que recuerda que un modelo es nuestra conexión con una tabla en la base de datos.
Antes de comenzar
Recuerda que aquí no vamos a tratar como trabajar con SQLAlchemy para realizar las conexiones sobre nuestra base de datos con nuestro proyecto en Flask, simplemente vamos a realizar las consultas tipo CRUD para operar la base de datos.
Seguramente te estás preguntando porqué necesitamos dos clases y no solo una, la respuesta se debe a la definición de en las rutas, por lo tanto vamos a tener:
- Una clase para los métodos que NO necesiten de una pk o id para poder operar
- Una clase para los métodos que SÍ necesiten de una pk o id para poder operar
Por lo tanto las rutas y configuración que hacemos quedan así:
from flask_restful import Api
from proyect_app.rest.controllers import BookApi, BookApiId
api = Api(app) #, decorators=[csrf.exempt]
api.add_resource(BookApi, '/api/book')
api.add_resource(BookApiId, '/api/book/<string:id>')Así que vamos a crear una para trabajar sin los IDs o PKs; como puedes suponer, esto serían para los métodos de Post, para crear un registro y para get, para obtener TODOS los registros.
Vamos a trabajar con el siguiente modelo:
class Category(db.Model):
__tablename__ = 'categories'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255))Funcionalidades adicionales sobre nuestro paquete
Nuestro paquete para lograr una Api Restful, trae varios elementos interesantes que nos facilitan bastante la vida para crear este tipo de APIs tipo CRUD.
Método POST: crear nuevos recursos
@marshal_with(resource_fields, envelope="categoria")
def post(self):
parser = reqparse.RequestParser()
parser.add_argument('name', required=True, help="No mandaste el nombre")
args = parser.parse_args()
c = Category(args['name'])
db.session.add(c)
db.session.commit()Aquí vamos a trabajar para crear un registro, así que vamos a crear otra clase que SI van a trabajar con los IDs:
Método GET: obtener todos los registros
@marshal_with(resource_fields, envelope="categorias")
def get(self):
return Category.query.all()Aquí vamos a devolver un registro por su identificador:
Métodos PATCH/PUT: actualizar datos
@marshal_with(resource_fields, envelope="categoria")
def patch(self, id):
parser = reqparse.RequestParser()
parser.add_argument('name', required=True)
args = parser.parse_args()
c = Category.query.get_or_404(id)
c.name = args['name']
db.session.commit()
return cMétodo DELETE: eliminar un registro
def delete(self, id):
c = Category.query.get_or_404(id)
db.session.delete(c)
db.session.commit()
return {'msj': 'ok'}Finalmente, todo el código de ambas clases:
from flask import request
from flask_restful import Resource, abort, reqparse, fields, marshal_with
from flask_httpauth import HTTPBasicAuth
from my_app.product.models import Category
from my_app.auth.model.user import User
from my_app import user_manager
from my_app import db
resource_fields = {
'id': fields.Integer,
'name' : fields.String
}
auth = HTTPBasicAuth()
@auth.verify_password
def verify_password(username, password):
user = User.query.filter_by(username=username).first()
if not user or not user_manager.verify_password(password_hash=user.password, password=password):
return False
return True
class Base:
def category_to_json(self,category):
return {
'id': category.id,
'name': category.name,
}
def abort_if_doesnt_exist(self, id, json=True):
category = Category.query.get(id)
if category is None:
abort(404, message="Categoría {} no existe".format(id))
if json:
return self.category_to_json(category)
return category
class CategoryRestFul(Resource,Base):
@auth.login_required
@marshal_with(resource_fields, envelope="categoria")
def get(self, id):
return self.abort_if_doesnt_exist(id,False)
@marshal_with(resource_fields, envelope="categoria")
def patch(self, id):
parser = reqparse.RequestParser()
parser.add_argument('name', required=True, help="No mandastes el nombre") args = parser.parse_args()
c = self.abort_if_doesnt_exist(id, False)
c.name = args['name'] #request.form
db.session.add(c)
db.session.commit()
return self.abort_if_doesnt_exist(c.id,False)
def delete(self, id):
c = self.abort_if_doesnt_exist(id, False)
db.session.delete(c)
db.session.commit()
return {'msj':'ok'}
class CategoryRestFulList(Resource,Base):
@marshal_with(resource_fields, envelope="categorias")
def get(self):
return Category.query.all()
@marshal_with(resource_fields, envelope="categoria")
def post(self):
parser = reqparse.RequestParser()
parser.add_argument('name',required=True, help="No mandastes el nombre")
args = parser.parse_args()
c = Category(args['name'])
db.session.add(c)
db.session.commit()
return c
class CategoryRestFulListSearch(Resource,Base):
@marshal_with(resource_fields, envelope="categoria")
def get(self):
parser = reqparse.RequestParser()
parser.add_argument('search',required=True, help="Tienes que especificar la busqueda")
args = parser.parse_args()
return Category.query.filter(Category.name.like('%{0}%'.format(args['search']))).all()Otras funcionalidades
Vamos a crear una clase auxiliar que nos permitirá agregar algunas funcionalidades adicionales sobre las clases tipo rest; por ejemplo, la de protección con login.
Y aquí definir nuestros métodos
@marshal_with(resource_fields, envelope="categorias")
def get(self):
return Category.query.all()Con esta función vamos a obtener todos los registros de nuestra base de datos:
Puntos a tener en cuenta
Como puedes ver, las operaciones que hacemos en la Rest Api no tienen nada de raro, algunas validaciones, operaciones sobre la base de datos y poco más, pero como puedes ver, tenemos un mecanismo bastante práctico para manipular u obtener los datos de nuestro usuario; los datos que nos pasa vía un formulario, una petición axio, o cualquier Api que emplees para mandar datos vía HTTP, los obtenemos mediante la clase de RequestParser; lo ideal de esto, es que nosotros podemos definir validaciones en la eficiente de la función add_argument y por lo tanto podemos estar 100 por ciento seguro que los datos que estamos trabajando son válidos.
Seguridad y Autenticación requerida en la Restful con Flask
Como puedes ver, estamos empleando una función que a la final funciona como decorador sobre nuestros recursos Rest para hacer la autenticación requerida sobre nuestra Rest Api; esto es un paquete de un tercero que puedes adaptar a otro tipo de servicios pero que funciona bastante bien con Flask Restful; simplemente tenemos que definir una función base en la cual realizamos las operaciones sobre nuestro modelo de usuarios, sea lo que sea que quieras verificar en la fase de autenticación requerida de la Rest Api lo puedes definir en esa función.
En este ejemplo tenemos un sencillo ejemplo en el cual buscamos primero por el username y su existe luego verificamos la contraseña que están en formato hash en la base de datos, por lo tanto, es una función que se encarga de hacer un login manual, y que empleamos perfectamente en nuestra Rest Api como autenticación requerida.
@auth.verify_password
def verify_password(username, password):
user = User.query.filter_by(username=username).first()
if not user or not user_manager.verify_password(password_hash=user.password, password=password):
return False
return TrueRecuerda que para emplear este paquete de autenticación tienes que instalarlo con:
pip install Flask-HTTPAuthConclusión
En mi experiencia desarrollando APIs RESTful con Flask, aprendí que usar flask-restful reduce mucho el esfuerzo de mantener el código limpio y modular. Separar las clases según usen o no id, validar la entrada con reqparse y proteger las rutas con HTTPAuth son prácticas que marcan la diferencia entre un prototipo y una API lista para producción.
Preguntas frecuentes (FAQ)
¿Qué diferencia hay entre Flask y Flask-Restful?
Flask es el microframework base; Flask-Restful agrega una capa que facilita la creación de APIs estructuradas con recursos y métodos HTTP.
¿Cómo puedo proteger mi API con autenticación por tokens?
Puedes integrar Flask-JWT o Flask-JWT-Extended para manejar tokens JWT en lugar de autenticación básica.
¿Flask es recomendable para proyectos grandes?
Sí, pero requiere modularización: dividir la app en blueprints y usar una arquitectura clara de paquetes.
¿Cómo probar mi API con Postman o cURL?
Con Postman puedes enviar peticiones a cada endpoint; con cURL, usa comandos como curl -X GET http://localhost:5000/api/book.
Acepto recibir anuncios de interes sobre este Blog.
Vamos a aprender a crear una Api Restful en Flask fácilmente empleando el paquete llamado flask_restful que como su nombre indica nos permite crear una Api Rest de tipo CRUD fácilmente.