46. Rest Api¶
46.1 Definir un Rest Api¶
Un buen diseño de una API REST se caracteriza por ser intuitivo, escalable, y fácil de usar, siguiendo una serie de mejores prácticas y principios de diseño. Aquí se destacan algunos aspectos clave para diseñar una API REST eficaz:
- Uso Correcto de los Métodos HTTP
- GET para recuperar recursos.
- POST para crear nuevos recursos.
- PUT para actualizar recursos existentes.
- DELETE para eliminar recursos.
-
PATCH para realizar actualizaciones parciales en un recurso.
-
Nombres de Ruta Basados en Recursos Las rutas deben ser sustantivos y no verbos. Por ejemplo, usar /users para acceder a recursos de usuarios y /users/{id} para acceder a un usuario específico. Las rutas deben reflejar relaciones jerárquicas cuando sea relevante, por ejemplo, /users/{userId}/posts para los posts de un usuario específico.
-
Respuestas Estandarizadas y Códigos de Estado HTTP Utilizar códigos de estado HTTP para comunicar el resultado de las operaciones, como 200 OK, 201 Created, 404 Not Found, y 500 Internal Server Error. Proporcionar mensajes de error claros y útiles en el cuerpo de la respuesta para facilitar la depuración por parte de los consumidores de la API.
-
Versionado de la API Versionar la API para gestionar cambios y evolución sin romper las aplicaciones cliente. Esto puede hacerse en la URL (por ejemplo, /api/v1/resource), en los encabezados HTTP, o mediante el uso de parámetros de consulta.
-
Uso de HATEOAS (Hypermedia as the Engine of Application State) Opcionalmente, incluir enlaces a acciones relacionadas o recursos dentro de las respuestas para promover la descubrimiento de la API y hacerla más navegable.
-
Seguridad Implementar autenticación (por ejemplo, mediante tokens JWT) y autorización para proteger los recursos. Usar HTTPS para encriptar los datos entre el cliente y el servidor.
-
Documentación Clara y Completa Proporcionar documentación detallada que incluya descripciones de rutas, métodos, parámetros, y ejemplos de respuestas. Herramientas como Swagger (OpenAPI) pueden automatizar gran parte de este proceso.
-
Paginación, Filtrado, y Ordenación Ofrecer paginación para respuestas que puedan retornar grandes cantidades de datos.
Permitir filtrado y ordenación de recursos para facilitar a los consumidores de la API la obtención de datos específicos. -
Rendimiento y Caché Considerar el uso de cabeceras HTTP para caché para reducir la carga en el servidor y mejorar la experiencia del usuario.
46.1.1 EndPoint: Punto de terminación.¶
Algunos consejos Previos:
- Las llamadas rest api se hacen indicando la dirección del servidor más una ruta a la entidad.
-
Mantén los Identificadores Opacos Los identificadores deben ser opacos desde la perspectiva del cliente de la API, lo que significa que no deben contener información interpretable o sensible. Esto ayuda a mantener la abstracción de la API y protege la privacidad y seguridad de los datos.
-
Uso de Identificadores en URLs Para relacionar entidades, utiliza identificadores en las URLs de forma jerárquica cuando sea apropiado. Por ejemplo, /users/{userId}/posts/{postId} para acceder a un post específico de un usuario.
-
[TODO] REVISAR Los UUIDs (Universally Unique Identifier) son una buena opción para garantizar la unicidad global sin necesidad de coordinación centralizada. Son especialmente útiles en sistemas distribuidos y pueden ayudar a evitar problemas de escalabilidad con secuencias numéricas autoincrementales.
46.1.1.1 Cuando manejamos relaciones¶
Cuando una entidad está relacionada con otra, normalmente tendremos un campo con un identificador que nos permite obtener la segunda entidad. Por ejemplo tenemos Profesores y Cursos con relación varios a varios.
{
"nombre": "Pepe",
"curso": "1"
}
Diseño de Endpoints para Relaciones Muchos-a-Muchos 1. Listar Entidades Relacionadas Para listar todas las clases que imparte un profesor específico o para listar todos los profesores de una clase específica, podrías diseñar endpoints como los siguientes:
Listar clases impartidas por un profesor específico: GET /profesores/{profesorId}/clases
Listar profesores de una clase específica: GET /clases/{claseId}/profesores
Estos endpoints permiten recuperar las entidades relacionadas de un lado de la relación.
- Añadir una Relación Para crear una nueva relación entre un profesor y una clase (es decir, asignar un profesor a una clase o viceversa), necesitarías endpoints que permitan especificar las entidades que se van a relacionar. Esto puede lograrse mediante:
Asignar un profesor a una clase: POST /clases/{claseId}/profesores Body: { "profesorId": [id] }
Asignar una clase a un profesor: POST /profesores/{profesorId}/clases Body: { "claseId": [id] }
Dependiendo de la lógica de tu aplicación y del modelo de datos, podrías implementar solo uno de estos enfoques o ambos.
- Eliminar una Relación Para eliminar una relación existente entre un profesor y una clase, podrías usar endpoints similares a los de añadir una relación, pero con el método HTTP DELETE:
Eliminar un profesor de una clase: DELETE /clases/{claseId}/profesores/{profesorId}
Eliminar una clase de un profesor: DELETE /profesores/{profesorId}/clases/{claseId}
Consideraciones Adicionales Modelo de Datos: Asegúrate de que tu modelo de datos (en el backend) soporte adecuadamente las relaciones muchos-a-muchos, típicamente a través de una tabla de unión que almacene las relaciones entre los identificadores de las entidades. Integridad de Datos: Implementa validaciones para evitar duplicados en las asignaciones y para manejar correctamente los intentos de eliminar relaciones que no existen. Seguridad: Considera los aspectos de seguridad, como la autenticación y autorización, para asegurarte de que solo los usuarios autorizados puedan modificar las relaciones. Documentación: Documenta claramente estos endpoints, incluyendo detalles sobre los parámetros requeridos y el formato de los datos de solicitud y respuesta.
Ejemplo de respuesta:
[
{
"claseId": 1,
"nombreClase": "Matemáticas Avanzadas",
"descripcion": "Una introducción a conceptos avanzados de matemáticas."
},
{
"claseId": 2,
"nombreClase": "Historia de la Ciencia",
"descripcion": "Exploración de los desarrollos científicos a través de la historia."
}
]
46.2 Ejemplo¶
Entidades y Relaciones
*Profesores: Entidad que representa a los profesores. *Alumnos: Entidad que representa a los alumnos. *Clases: Entidad que representa las clases. Cada clase es impartida por un profesor y tiene varios alumnos inscritos.
Profesores Listar profesores: GET /profesores
Devuelve una lista de todos los profesores.
Obtener detalles de un profesor: GET /profesores/{profesorId}
Devuelve los detalles de un profesor específico. Crear un nuevo profesor: POST /profesores
Crea un nuevo profesor. Actualizar un profesor: PUT /profesores/{profesorId}
Actualiza los detalles de un profesor específico. Eliminar un profesor: DELETE /profesores/{profesorId}
Elimina un profesor específico.
Listar clases de un profesor: GET /profesores/{profesorId}/clases
Devuelve las clases impartidas por un profesor específico.
Alumnos Listar alumnos: GET /alumnos
Devuelve una lista de todos los alumnos. Obtener detalles de un alumno: GET /alumnos/{alumnoId}
Devuelve los detalles de un alumno específico. Crear un nuevo alumno: POST /alumnos
Crea un nuevo alumno. Actualizar un alumno: PUT /alumnos/{alumnoId}
Actualiza los detalles de un alumno específico. Eliminar un alumno: DELETE /alumnos/{alumnoId}
Elimina un alumno específico. Listar clases de un alumno: GET /alumnos/{alumnoId}/clases
Devuelve las clases en las que está inscrito un alumno específico. Clases Listar clases: GET /clases
Devuelve una lista de todas las clases. Obtener detalles de una clase: GET /clases/{claseId}
Devuelve los detalles de una clase específica, incluyendo el profesor que la imparte y los alumnos inscritos. Crear una nueva clase: POST /clases
Crea una nueva clase. Actualizar una clase: PUT /clases/{claseId}
Actualiza los detalles de una clase específica. Eliminar una clase: DELETE /clases/{claseId}
Elimina una clase específica.
Podemos modelizar relaciones usando uno de estos métodos:
- Enviar el ID del Alumno en el Cuerpo de la Petición (Payload) El cuerpo de la petición (request body) podría contener el ID del alumno, o incluso un objeto alumno más completo si fuera necesario para la operación. Este enfoque es útil si necesitas pasar información adicional sobre la inscripción, además del ID del alumno.
Ejemplo de un cuerpo de petición con el ID del alumno:
{
"alumnoId": 123
}
- . Enviar el ID del Alumno como parte de la URL Aunque el enfoque más común para una operación de este tipo es enviar el ID del alumno en el cuerpo de la petición, en algunos casos, podrías considerar pasar el ID del alumno como parte de la URL, especialmente si la operación se limita estrictamente a la inscripción de un alumno sin necesidad de información adicional.
Ejemplo de URL para este enfoque:
POST /clases/{claseId}/alumnos/{alumnoId}
Get resumen y detalle
Crear un endpoint en tu API que devuelva información detallada como el nombre del profesor y el nombre de la clase, en lugar de solo los identificadores, puede ser muy útil en ciertos contextos. Este enfoque mejora la legibilidad y usabilidad de la API para los consumidores, ya que proporciona información más rica y relevante en una sola llamada, lo cual puede reducir la necesidad de realizar múltiples solicitudes para obtener detalles relacionados.
Ventajas Eficiencia: Reduce el número de llamadas a la API necesarias para obtener información relacionada, lo cual es especialmente beneficioso en entornos con limitaciones de red o donde el rendimiento es una consideración crítica. Usabilidad: Mejora la experiencia del desarrollador al consumir la API, proporcionando datos más completos y listos para usar. Integración: Facilita la integración con otras aplicaciones o servicios que requieren información compuesta sin el overhead de realizar el ensamblaje de datos del lado del cliente. Consideraciones Diseño del Endpoint: Podrías diseñar un endpoint específico para este propósito, por ejemplo, GET /clases/detalles o GET /clases/{claseId}/detalle, que devuelva los nombres de las clases junto con los nombres de los profesores asociados. Selección de Datos: Decide cuidadosamente qué datos incluir en la respuesta para evitar sobrecargar al cliente con información innecesaria. En este caso, el nombre de la clase y el nombre del profesor son directamente relevantes y útiles. Documentación: Asegúrate de documentar claramente este endpoint, especificando el formato de la respuesta y describiendo cada uno de los campos retornados.
Ejemplo de respuesta:
[
{
"claseId": 1,
"nombreClase": "Matemáticas Avanzadas",
"profesor": {
"profesorId": 101,
"nombreProfesor": "Juan Pérez"
}
},
{
"claseId": 2,
"nombreClase": "Historia Contemporánea",
"profesor": {
"profesorId": 102,
"nombreProfesor": "Laura Gómez"
}
}
]
46.2.1 Operaciones¶
Listar Profesores de una Clase Específica Solicitud: No es necesario un cuerpo de solicitud para una operación GET.
[
{
"profesorId": 101,
"nombre": "Juan Pérez",
"especialidad": "Matemáticas"
},
{
"profesorId": 102,
"nombre": "Laura Gómez",
"especialidad": "Historia"
}
]
Para los endpoints de una relación muchos-a-muchos entre profesores y clases, los JSON utilizados en las solicitudes y respuestas dependerán de las operaciones específicas realizadas. A continuación, se muestran ejemplos de cómo podrían estructurarse estos JSON para diferentes operaciones:
- Listar Clases Impartidas por un Profesor Específico Solicitud: No es necesario un cuerpo de solicitud para una operación GET.
Respuesta:
json Copy code [ { "claseId": 1, "nombreClase": "Matemáticas Avanzadas", "descripcion": "Una introducción a conceptos avanzados de matemáticas." }, { "claseId": 2, "nombreClase": "Historia de la Ciencia", "descripcion": "Exploración de los desarrollos científicos a través de la historia." } ] 2. Listar Profesores de una Clase Específica Solicitud: No es necesario un cuerpo de solicitud para una operación GET.
Respuesta:
json
Copy code
[
{
"profesorId": 101,
"nombre": "Juan Pérez",
"especialidad": "Matemáticas"
},
{
"profesorId": 102,
"nombre": "Laura Gómez",
"especialidad": "Historia"
}
]
3. Asignar un Profesor a una Clase
Solicitud (para añadir un profesor a una clase específica):
json
{
"profesorId": 101
}
Eliminar un Profesor de una Clase
Para una operación DELETE, no se envía un cuerpo JSON en la solicitud. La operación se especifica completamente a través de la URL.
Solicitud: DELETE /clases/{claseId}/profesores/{profesorId}
Respuesta: La respuesta a una operación DELETE podría ser un código de estado HTTP 204 (No Content) indicando que la acción se completó con éxito, sin cuerpo de respuesta.
46.3 Rest api Cliente¶
46.3.1 RApi cliente Python¶
Un artículo con varias librerías y frameworks, incluyendo el más simple y de bajo nivel con requests.
Otro librería sin mantenimiento y orientada a clientes rest api es slumber, en gitlab