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

  1. Introducción a las APIs REST
  2. Instalación y Configuración de Flask
  3. Creación de Rutas y Endpoints
  4. Manejo de Solicitudes y Respuestas
  5. Conexión a una Base de Datos
  6. Autenticación y Autorización
  7. Pruebas de la API
  8. Conclusión

  1. 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.

  1. Instalación y Configuración de Flask

Primero, necesitas instalar Flask. Puedes hacerlo utilizando pip:

pip install Flask

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:

python app.py

Visita http://127.0.0.1:5000/ en tu navegador para ver la aplicación en funcionamiento.

  1. 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.

  1. 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}), 201

Actualizar 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})

  1. 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

pip install Flask-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})

  1. 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

pip install 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]})

  1. Pruebas de la API

Para probar tu API, puedes usar herramientas como Postman o escribir pruebas automatizadas con unittest.

Prueba con Postman

  1. GET /tasks: Verifica que puedes obtener la lista de tareas.
  2. POST /tasks: Crea una nueva tarea y verifica que se añade correctamente.
  3. PUT /tasks/{id}: Actualiza una tarea existente.
  4. 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()

  1. 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

Módulo 2: Estructuras de Control

Módulo 3: Funciones y Módulos

Módulo 4: Estructuras de Datos

Módulo 5: Programación Orientada a Objetos

Módulo 6: Manejo de Archivos

Módulo 7: Manejo de Errores y Excepciones

Módulo 8: Temas Avanzados

Módulo 9: Pruebas y Depuración

Módulo 10: Desarrollo Web con Python

Módulo 11: Ciencia de Datos con Python

Módulo 12: Proyecto Final

© Copyright 2024. Todos los derechos reservados