En este tema, aprenderás a construir APIs RESTful utilizando Flask, un microframework de Python. Flask es conocido por su simplicidad y flexibilidad, lo que lo hace ideal para desarrollar aplicaciones web y APIs.
Contenido
- Introducción a las APIs REST
- Instalación y Configuración de Flask
- Creación de Rutas y Endpoints
- Manejo de Solicitudes y Respuestas
- Conexión a una Base de Datos
- Autenticación y Autorización
- Pruebas de la API
- Conclusión
- Introducción a las APIs REST
Las APIs REST (Representational State Transfer) son un estilo arquitectónico para diseñar servicios web. Utilizan métodos HTTP y se basan en recursos, que son identificados por URLs.
Conceptos Clave
- Recursos: Entidades que se pueden crear, leer, actualizar y eliminar (CRUD).
- Métodos HTTP:
- GET: Obtener datos.
- POST: Crear un nuevo recurso.
- PUT: Actualizar un recurso existente.
- DELETE: Eliminar un recurso.
 
- Endpoints: URLs que representan recursos y permiten interactuar con ellos.
- Instalación y Configuración de Flask
Primero, necesitas instalar Flask. Puedes hacerlo utilizando pip:
Configuración Básica
Crea un archivo llamado app.py y configura una aplicación Flask básica:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
    return 'Hello, World!'
if __name__ == '__main__':
    app.run(debug=True)Ejecuta el archivo con:
Visita http://127.0.0.1:5000/ en tu navegador para ver la aplicación en funcionamiento.
- Creación de Rutas y Endpoints
Vamos a crear una API para gestionar una lista de tareas (To-Do List).
Definición de Rutas
from flask import Flask, jsonify, request
app = Flask(__name__)
tasks = [
    {'id': 1, 'title': 'Learn Flask', 'description': 'Learn how to build APIs with Flask', 'done': False},
    {'id': 2, 'title': 'Build an API', 'description': 'Build a RESTful API using Flask', 'done': False}
]
@app.route('/tasks', methods=['GET'])
def get_tasks():
    return jsonify({'tasks': tasks})
@app.route('/tasks/<int:task_id>', methods=['GET'])
def get_task(task_id):
    task = next((task for task in tasks if task['id'] == task_id), None)
    if task is None:
        return jsonify({'error': 'Task not found'}), 404
    return jsonify({'task': task})
if __name__ == '__main__':
    app.run(debug=True)Explicación del Código
- @app.route('/tasks', methods=['GET']): Define una ruta para obtener todas las tareas.
- @app.route('/tasks/<int:task_id>', methods=['GET']): Define una ruta para obtener una tarea específica por su ID.
- jsonify: Convierte los datos de Python en JSON.
- Manejo de Solicitudes y Respuestas
Crear una Nueva Tarea
@app.route('/tasks', methods=['POST'])
def create_task():
    if not request.json or not 'title' in request.json:
        return jsonify({'error': 'Bad Request'}), 400
    task = {
        'id': tasks[-1]['id'] + 1,
        'title': request.json['title'],
        'description': request.json.get('description', ""),
        'done': False
    }
    tasks.append(task)
    return jsonify({'task': task}), 201Actualizar una Tarea
@app.route('/tasks/<int:task_id>', methods=['PUT'])
def update_task(task_id):
    task = next((task for task in tasks if task['id'] == task_id), None)
    if task is None:
        return jsonify({'error': 'Task not found'}), 404
    if not request.json:
        return jsonify({'error': 'Bad Request'}), 400
    task['title'] = request.json.get('title', task['title'])
    task['description'] = request.json.get('description', task['description'])
    task['done'] = request.json.get('done', task['done'])
    return jsonify({'task': task})Eliminar una Tarea
@app.route('/tasks/<int:task_id>', methods=['DELETE'])
def delete_task(task_id):
    task = next((task for task in tasks if task['id'] == task_id), None)
    if task is None:
        return jsonify({'error': 'Task not found'}), 404
    tasks.remove(task)
    return jsonify({'result': True})
- Conexión a una Base de Datos
Para almacenar datos de manera persistente, puedes conectar tu API a una base de datos. Aquí usaremos SQLite con SQLAlchemy.
Instalación de SQLAlchemy
Configuración de SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///tasks.db'
db = SQLAlchemy(app)
class Task(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(80), nullable=False)
    description = db.Column(db.String(200), nullable=True)
    done = db.Column(db.Boolean, default=False)
db.create_all()CRUD con SQLAlchemy
Actualiza las rutas para interactuar con la base de datos:
@app.route('/tasks', methods=['GET'])
def get_tasks():
    tasks = Task.query.all()
    return jsonify({'tasks': [task.to_dict() for task in tasks]})
@app.route('/tasks/<int:task_id>', methods=['GET'])
def get_task(task_id):
    task = Task.query.get(task_id)
    if task is None:
        return jsonify({'error': 'Task not found'}), 404
    return jsonify({'task': task.to_dict()})
@app.route('/tasks', methods=['POST'])
def create_task():
    if not request.json or not 'title' in request.json:
        return jsonify({'error': 'Bad Request'}), 400
    task = Task(
        title=request.json['title'],
        description=request.json.get('description', ""),
        done=False
    )
    db.session.add(task)
    db.session.commit()
    return jsonify({'task': task.to_dict()}), 201
@app.route('/tasks/<int:task_id>', methods=['PUT'])
def update_task(task_id):
    task = Task.query.get(task_id)
    if task is None:
        return jsonify({'error': 'Task not found'}), 404
    if not request.json:
        return jsonify({'error': 'Bad Request'}), 400
    task.title = request.json.get('title', task.title)
    task.description = request.json.get('description', task.description)
    task.done = request.json.get('done', task.done)
    db.session.commit()
    return jsonify({'task': task.to_dict()})
@app.route('/tasks/<int:task_id>', methods=['DELETE'])
def delete_task(task_id):
    task = Task.query.get(task_id)
    if task is None:
        return jsonify({'error': 'Task not found'}), 404
    db.session.delete(task)
    db.session.commit()
    return jsonify({'result': True})
- Autenticación y Autorización
Para proteger tu API, puedes implementar autenticación y autorización. Aquí usaremos tokens JWT (JSON Web Tokens).
Instalación de Flask-JWT-Extended
Configuración de JWT
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity
app.config['JWT_SECRET_KEY'] = 'your_secret_key'
jwt = JWTManager(app)
@app.route('/login', methods=['POST'])
def login():
    if not request.json or not 'username' in request.json or not 'password' in request.json:
        return jsonify({'error': 'Bad Request'}), 400
    username = request.json['username']
    password = request.json['password']
    # Aquí deberías verificar el usuario y la contraseña
    access_token = create_access_token(identity=username)
    return jsonify(access_token=access_token), 200
@app.route('/tasks', methods=['GET'])
@jwt_required()
def get_tasks():
    current_user = get_jwt_identity()
    tasks = Task.query.all()
    return jsonify({'tasks': [task.to_dict() for task in tasks]})
- Pruebas de la API
Para probar tu API, puedes usar herramientas como Postman o escribir pruebas automatizadas con unittest.
Prueba con Postman
- GET /tasks: Verifica que puedes obtener la lista de tareas.
- POST /tasks: Crea una nueva tarea y verifica que se añade correctamente.
- PUT /tasks/{id}: Actualiza una tarea existente.
- DELETE /tasks/{id}: Elimina una tarea.
Pruebas Automatizadas
import unittest
import json
from app import app, db, Task
class APITestCase(unittest.TestCase):
    def setUp(self):
        self.app = app.test_client()
        db.create_all()
    def tearDown(self):
        db.session.remove()
        db.drop_all()
    def test_get_tasks(self):
        response = self.app.get('/tasks')
        self.assertEqual(response.status_code, 200)
    def test_create_task(self):
        response = self.app.post('/tasks', data=json.dumps({'title': 'Test Task'}), content_type='application/json')
        self.assertEqual(response.status_code, 201)
if __name__ == '__main__':
    unittest.main()
- Conclusión
En este tema, has aprendido a construir una API RESTful utilizando Flask. Has cubierto desde la creación de rutas y endpoints hasta la conexión a una base de datos y la implementación de autenticación. Además, has visto cómo probar tu API para asegurarte de que funciona correctamente.
Resumen
- APIs REST: Estilo arquitectónico para diseñar servicios web.
- Flask: Microframework de Python para desarrollar aplicaciones web y APIs.
- SQLAlchemy: ORM para interactuar con bases de datos.
- JWT: Método para autenticación y autorización.
Con estos conocimientos, estás preparado para construir y desplegar tus propias APIs RESTful utilizando Flask. ¡Sigue practicando y explorando más funcionalidades avanzadas de Flask y sus extensiones!
Curso de Programación en Python
Módulo 1: Introducción a Python
- Introducción a Python
- Configuración del Entorno de Desarrollo
- Sintaxis de Python y Tipos de Datos Básicos
- Variables y Constantes
- Entrada y Salida Básica
Módulo 2: Estructuras de Control
- Sentencias Condicionales
- Bucles: for y while
- Herramientas de Control de Flujo
- Comprensiones de Listas
Módulo 3: Funciones y Módulos
- Definición de Funciones
- Argumentos de Función
- Funciones Lambda
- Módulos y Paquetes
- Visión General de la Biblioteca Estándar
Módulo 4: Estructuras de Datos
Módulo 5: Programación Orientada a Objetos
Módulo 6: Manejo de Archivos
- Lectura y Escritura de Archivos
- Trabajo con Archivos CSV
- Manejo de Datos JSON
- Operaciones de Archivos y Directorios
Módulo 7: Manejo de Errores y Excepciones
- Introducción a las Excepciones
- Manejo de Excepciones
- Lanzamiento de Excepciones
- Excepciones Personalizadas
Módulo 8: Temas Avanzados
- Decoradores
- Generadores
- Administradores de Contexto
- Concurrencia: Hilos y Procesos
- Asyncio para Programación Asíncrona
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias con unittest
- Desarrollo Guiado por Pruebas
- Técnicas de Depuración
- Uso de pdb para Depuración
Módulo 10: Desarrollo Web con Python
- Introducción al Desarrollo Web
- Fundamentos del Framework Flask
- Construcción de APIs REST con Flask
- Introducción a Django
- Construcción de Aplicaciones Web con Django
Módulo 11: Ciencia de Datos con Python
- Introducción a la Ciencia de Datos
- NumPy para Computación Numérica
- Pandas para Manipulación de Datos
- Matplotlib para Visualización de Datos
- Introducción al Aprendizaje Automático con scikit-learn
