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_userrecibe 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'}), 404Explicación:
- Método HTTP: GET
- URI: /users/{id}
- Función:
get_userbusca 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), 201Explicación:
- Método HTTP: POST
- URI: /posts
- Función:
create_postrecibe 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), 201Explicación:
- Método HTTP: POST
- URI: /users/{id}/follow
- Función:
follow_userrecibe 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'}), 404Explicación:
- Método HTTP: POST
- URI: /posts/{id}/likes
- Función:
like_postincrementa 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'}), 401Explicación:
- Método HTTP: POST
- URI: /login
- Función:
loginverifica 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 decoratedExplicación:
- Función:
token_requiredes 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
passExplicación:
- Función:
create_postahora 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'}), 500Explicación:
- Función:
not_foundyinternal_errormanejan 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
/userscon datos JSON del usuario. - Iniciar sesión: Enviar una solicitud POST a
/logincon las credenciales del usuario. - Crear una publicación: Enviar una solicitud POST a
/postscon 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}/likescon 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
