En este caso de estudio, vamos a diseñar y desarrollar una API RESTful para una red social básica. La API permitirá a los usuarios registrarse, iniciar sesión, crear publicaciones, seguir a otros usuarios y dar "me gusta" a las publicaciones. Este ejercicio práctico consolidará los conceptos aprendidos en los módulos anteriores.
Objetivos del Caso de Estudio
- Diseñar los recursos y URIs necesarios para la API.
- Implementar los métodos HTTP adecuados para cada recurso.
- Manejar la autenticación y autorización de usuarios.
- Gestionar errores y respuestas adecuadas.
- Probar y validar la API.
- Diseño de Recursos y URIs
Recursos Principales
- Usuarios
- Publicaciones
- Seguidores
- Likes
Estructura de URIs
Recurso | URI | Método HTTP | Descripción |
---|---|---|---|
Usuarios | /users | POST | Crear un nuevo usuario |
Usuarios | /users/{id} | GET | Obtener información de un usuario |
Usuarios | /users/{id} | PUT | Actualizar información de un usuario |
Usuarios | /users/{id} | DELETE | Eliminar un usuario |
Publicaciones | /posts | POST | Crear una nueva publicación |
Publicaciones | /posts/{id} | GET | Obtener una publicación |
Publicaciones | /posts/{id} | DELETE | Eliminar una publicación |
Seguidores | /users/{id}/followers | GET | Obtener seguidores de un usuario |
Seguidores | /users/{id}/follow | POST | Seguir a un usuario |
Seguidores | /users/{id}/unfollow | POST | Dejar de seguir a un usuario |
Likes | /posts/{id}/likes | POST | Dar "me gusta" a una publicación |
Likes | /posts/{id}/likes | DELETE | Quitar "me gusta" de una publicación |
- Implementación de Métodos HTTP
Crear un Nuevo Usuario
from flask import Flask, request, jsonify app = Flask(__name__) users = [] @app.route('/users', methods=['POST']) def create_user(): user_data = request.get_json() new_user = { 'id': len(users) + 1, 'username': user_data['username'], 'email': user_data['email'], 'password': user_data['password'] # En una aplicación real, nunca almacenar contraseñas en texto plano } users.append(new_user) return jsonify(new_user), 201 if __name__ == '__main__': app.run(debug=True)
Explicación:
- Método HTTP: POST
- URI: /users
- Función:
create_user
recibe datos JSON del nuevo usuario, los almacena en una lista y devuelve el usuario creado con un código de estado 201.
Obtener Información de un Usuario
@app.route('/users/<int:id>', methods=['GET']) def get_user(id): user = next((u for u in users if u['id'] == id), None) if user: return jsonify(user) return jsonify({'error': 'User not found'}), 404
Explicación:
- Método HTTP: GET
- URI: /users/{id}
- Función:
get_user
busca un usuario por su ID y lo devuelve en formato JSON. Si no se encuentra, devuelve un error 404.
Crear una Nueva Publicación
posts = [] @app.route('/posts', methods=['POST']) def create_post(): post_data = request.get_json() new_post = { 'id': len(posts) + 1, 'user_id': post_data['user_id'], 'content': post_data['content'], 'likes': 0 } posts.append(new_post) return jsonify(new_post), 201
Explicación:
- Método HTTP: POST
- URI: /posts
- Función:
create_post
recibe datos JSON de una nueva publicación, la almacena en una lista y devuelve la publicación creada con un código de estado 201.
Seguir a un Usuario
follows = [] @app.route('/users/<int:id>/follow', methods=['POST']) def follow_user(id): follow_data = request.get_json() new_follow = { 'follower_id': follow_data['follower_id'], 'followed_id': id } follows.append(new_follow) return jsonify(new_follow), 201
Explicación:
- Método HTTP: POST
- URI: /users/{id}/follow
- Función:
follow_user
recibe datos JSON del seguidor y el usuario a seguir, los almacena en una lista y devuelve la relación de seguimiento creada con un código de estado 201.
Dar "Me Gusta" a una Publicación
@app.route('/posts/<int:id>/likes', methods=['POST']) def like_post(id): post = next((p for p in posts if p['id'] == id), None) if post: post['likes'] += 1 return jsonify(post) return jsonify({'error': 'Post not found'}), 404
Explicación:
- Método HTTP: POST
- URI: /posts/{id}/likes
- Función:
like_post
incrementa el contador de "me gusta" de una publicación y devuelve la publicación actualizada. Si no se encuentra la publicación, devuelve un error 404.
- Autenticación y Autorización
Para simplificar, utilizaremos un sistema básico de autenticación con tokens. En una aplicación real, se recomienda usar OAuth o JWT.
Generar un Token de Autenticación
import uuid tokens = {} @app.route('/login', methods=['POST']) def login(): login_data = request.get_json() user = next((u for u in users if u['username'] == login_data['username'] and u['password'] == login_data['password']), None) if user: token = str(uuid.uuid4()) tokens[token] = user['id'] return jsonify({'token': token}) return jsonify({'error': 'Invalid credentials'}), 401
Explicación:
- Método HTTP: POST
- URI: /login
- Función:
login
verifica las credenciales del usuario y, si son correctas, genera un token único y lo devuelve. Si las credenciales son incorrectas, devuelve un error 401.
Middleware de Autenticación
from functools import wraps def token_required(f): @wraps(f) def decorated(*args, **kwargs): token = request.headers.get('Authorization') if not token or token not in tokens: return jsonify({'error': 'Token is missing or invalid'}), 401 return f(*args, **kwargs) return decorated
Explicación:
- Función:
token_required
es un decorador que verifica la presencia y validez del token en las cabeceras de la solicitud. Si el token es inválido o falta, devuelve un error 401.
Aplicar Middleware a Rutas Protegidas
@app.route('/posts', methods=['POST']) @token_required def create_post(): # Código de la función create_post pass
Explicación:
- Función:
create_post
ahora está protegida por el middlewaretoken_required
, asegurando que solo los usuarios autenticados puedan crear publicaciones.
- Manejo de Errores y Respuestas
Ejemplo de Manejo de Errores
@app.errorhandler(404) def not_found(error): return jsonify({'error': 'Resource not found'}), 404 @app.errorhandler(500) def internal_error(error): return jsonify({'error': 'Internal server error'}), 500
Explicación:
- Función:
not_found
yinternal_error
manejan errores 404 y 500 respectivamente, devolviendo mensajes de error en formato JSON.
- Pruebas y Validación
Pruebas con Postman
- Crear un nuevo usuario: Enviar una solicitud POST a
/users
con datos JSON del usuario. - Iniciar sesión: Enviar una solicitud POST a
/login
con las credenciales del usuario. - Crear una publicación: Enviar una solicitud POST a
/posts
con datos JSON de la publicación y el token de autenticación en las cabeceras. - Dar "me gusta" a una publicación: Enviar una solicitud POST a
/posts/{id}/likes
con el token de autenticación en las cabeceras.
Validación de la API
- Verificar que las respuestas sean correctas y contengan los datos esperados.
- Asegurarse de que los errores se manejen adecuadamente y se devuelvan los códigos de estado correctos.
Conclusión
En este caso de estudio, hemos diseñado y desarrollado una API RESTful para una red social básica. Hemos cubierto la creación de recursos, la implementación de métodos HTTP, la autenticación y autorización, el manejo de errores y la validación de la API. Este ejercicio práctico refuerza los conceptos aprendidos y proporciona una base sólida para desarrollar APIs RESTful más complejas en el futuro.
Curso de REST API: Principios de Diseño y Desarrollo de APIs RESTful
Módulo 1: Introducción a las APIs RESTful
Módulo 2: Diseño de APIs RESTful
- Principios de diseño de APIs RESTful
- Recursos y URIs
- Métodos HTTP
- Códigos de estado HTTP
- Versionado de APIs
- Documentación de APIs
Módulo 3: Desarrollo de APIs RESTful
- Configuración del entorno de desarrollo
- Creación de un servidor básico
- Manejo de peticiones y respuestas
- Autenticación y autorización
- Manejo de errores
- Pruebas y validación
Módulo 4: Buenas Prácticas y Seguridad
- Buenas prácticas en el diseño de APIs
- Seguridad en APIs RESTful
- Rate limiting y throttling
- CORS y políticas de seguridad
Módulo 5: Herramientas y Frameworks
- Postman para pruebas de APIs
- Swagger para documentación
- Frameworks populares para APIs RESTful
- Integración continua y despliegue