En esa sección se proveen las guías y ejemplos para las API de los servicios del portal de Medellín Digital. Esta guía fomenta la consistencia, mantenibilidad y mejores prácticas a través de los difertenes servicios del portal.
Este documento se basa en:
REST es un estilo de arquitectura propuesto por Roy Fielding en el año 2000, que busca desacoplar el cliente y el servidor de una aplicación.
La arquitectura REST tiene cinco restricciones requeridas:
-
Cliente-Servidor: Una clara separación entre el cliente el servidor. Esto implica, por ejemplo, que los clientes no son responsables de almacenar datos y que los servidores no se encargan de la interfaz de usuario.
-
Sin estado: Toda comunicación entre el cliente y el servidor es independiente del contexto. En ninguna parte se almacena información sobre interacciones pasadas. Esto implica que cada petición del cliente al servidor debe incluir toda la información necesaria para contextualizar al servidor.
-
Cacheable: Las respuestas que envía el servidor pueden ser guardadas en cache. Debe existir un mecanismo para invalidar la respuesta y conseguir una verisón más reciente.
-
Sistema por capas: La petición puede pasar por varios sistemas antes de generar una respuesta. Estas pueden incluir un caché, un balanceador de carga, un proxy y finalmente el servidor. Esto tiene que ser transparente para el cliente.
-
Interfaz uniforme: Simplifica y desacopla la arquitectura entre el cliente y el servidor. Así, cada componente puede evolucionar de forma independiente.
La interfaz uniforme debe tener en cuenta los siguientes principios:
-
Identificación de Recursos: Los recursos son elementos de información que pueden ser accedidos por un identificador global (URI). Esto implica que el servidor no debe enviar los registros en base de datos "crudos", sino objetos que forman parte del dominio de la aplicación. Los recursos son enviados en una representación específica (XML, JSON, HTML).
-
Manipulación de los recursos a través de las representaciones: Cuando un cliente adquiere la representación de un recurso, tiene la información suficiente para modificarlo o eliminarlo en el servidor si tiene los permisos suficientes.
-
Mensajes auto-descriptivos: Todos los mensajes que se transmiten entre los componentes, tienen suficiente información para informar como deben ser manipulados. Esto incluye, por ejemplo, el formato (JSON, XML) en el que se espera recibir la representación del recurso.
-
Hypermedia como el motor del estado de la aplicación: HATEOAS por su nombre en inglés, significa que en todo momento, el servidor es quien envía al cliente las transiciones que puede realizar desde el estado en el que se = encuentra. Esto implica que la única dirección que conoce el cliente es la inicial (
root
de la API). Todas las otras peticiones se hacen dependiendo de la información enviada por el servidor.
Aún cuando lo ideal sería tener APIs 100% RESTful, se facilitan las siguientes excepciones:
-
La versión de la API puede estar en la URL. No se aceptan peticiones que no especifiquen la versión.
-
Permita que los usuarios pidan el formato desde la URL así:
-
Una URL identifica un recurso.
-
Una URL nunca tiene verbos. Siempre son sustantivos.
-
Usar sustantivos en plural para la consistencia.
-
Usar los verbos HTTP (GET, POST, PUT, DELETE) para operar sobre los recursos y colecciones.
-
Nunca se deben tener URLs con más de dos niveles de profundidad:
- Mal:
https://portal.ejemplo.com/api/v1/eventos/32/fotos/332/comentarios
- Bien:
https://portal.ejemplo.com/api/v1/fotos/332/comentarios
- Mal:
-
La versión debe ser siempre el primer parámetro en la URL
https://portal.ejemplo.com/api/v32/
. -
La versión siempre tiene que ser un número entero.
-
El formato debe ser de la forma
api/v3/recurso/{identificador}.{formato}
-
Una lista de eventos:
https://api.ejemplo.com/v1/eventos.json
-
Filtrando colecciones:
https://api.ejemplo.com/v1/eventos.json?ano=2013&order=desc
https://api.ejemplo.com/v1/picoyplaca.json?placa=2
-
Un solo recurso:
https://api.ejemplo.com/v1/eventos/3-pais-paisa.json
-
Recursos anidados: Por ejemplo, todas las fotos un evento específico.
https://api.ejemplo.com/v1/eventos/3-pais-paisa/fotos.json
-
Crear una nueva foto en un evento específico:
POST https://api.ejemplo.com/v1/eventos/3-pais-paisa/fotos.json
-
Nombre en singular:
https://api.ejemplo.com/v1/evento/3-pais-paisa.json
-
Verbos en la URL:
https://api.ejemplo.com/v1/eventos/3-pais-paisa/editar
-
Filtros como parte de la URL:
https://api.ejemplo.com/v1/eventos/2013
Los verbos utilizados al realizar la petición, darán al servidor el contexto necesario para saber qué manipulación se quiere hacer con los recursos.
HTTP METHOD | POST | GET | PUT | DELETE |
---|---|---|---|---|
CRUD OP | CREATE | READ | UPDATE | DELETE |
/perros | Crea un perro nuevo | Lista de perros | Actualización en bloque | borra todos los perros |
/perros/1234 | Error | Muestra el perro | Si existe, actualiza el perro; sino, error | borra al perro 1234 |
(Ejemplo de Web API Design, de Brian Mulloy, Apigee.)
-
No poner valores en las llaves.
-
No exponer valores privados ni nombres específicamente internos ("node", "taxonomy").
-
Los metadatos deben ser específicos a la respuesta. No a los miembros de ella.
-
Todos los recursos, en colecciones o no, deben tener un identificador relacionado donde el cliente puede pedir información sobre este recurso específico.
-
Todas las respuestas deben tener "metadata". Si es JSON, esto debe ser un objeto aparte. En ATOM (XML) y HTML se pueden utilizar los elementos de hypermedia definidos en los estándares.
GET /v1/articulos/32-nuevo-portal/etiquetas.json
{
"tags": [
{"nombre": "Medellín Digital", "url": "https://api.ejemplo.com/v1/etiquetas/324-medellin-digital"},
{"nombre": "Innovación", "url": "https://api.ejemplo.com/v1/etiquetas/24"}
],
"metadata": {
"links": [
{"rel": "self", "url": "/v1/articulos/32-nuevo-portal/etiquetas.json"},
{"rel": "articulo", "url": "/v1/articulos/32-nuevo-portal.json"}
]
}
}
GET /v1/articulos/32-nuevo-portal/etiquetas.json
{
"tags": [
{"324": "Medellín Digital"},
{"24": "Innovación"}
]
}
GET /v1/articulos/32-nuevo-portal/etiquetas.json
{
"tags": ["Medellín Digital", "Innovación"]
}
Las respuestas de errores deben incluir el código HTTP del error, un mensaje para los desarrolladores y uno para los usuarios (cuando sea necesario), un código de error interno (si aplica), vínculos donde los desarrolladores pueden encontrar información adicional (si aplica). Por ejemplo:
{
"status" : "400",
"developerMessage" : "Mensaje claro explicando al desarrollador el problema.
Dar sugerencias de como resolver el problema.",
"userMessage" : "Mensaje para mostrar a los usuarios, si es necesario.",
"errorCode" : "444444",
"mas info" : "http://www.example.gov/developer/path/to/help/for/444444,
http://drupal.org/node/444444",
}
HTTP tiene muchos códigos para responder a las peticiones. Los más utilizados son:
- 200 - OK: La operación fue completada con éxito.
- 201 - Creado: Se creó un recurso (se debe enviar en la respuesta).
- 304 - No modificado: El caché no ha expirado.
- 400 - Solicitud incorrecta: La solicitud contiene sintaxis errónea y no debería repetirse.
- 401 - No autorizado: El usuario no se ha autenticado o ha fallado en hacerlo.
- 403 - Prohibido: La solicitud fue legal, pero el servidor se rehúsa a responderla. En contraste a una respuesta 401 No autorizado, la autentificación no haría la diferencia.
- 500 - Error Interno: El servidor ha sufrido un error interno.
La lista completa se encuentra aquí.
- GET /articulos
- GET /articulos/{id}
- POST /articulos
GET /v1/articulos.json
{
"metadata": {
"links":{
[
{"rel": "next", "url": "https://api.ejemplo.com/v1/articulos.json?=page2"},
{"rel": "last", "url": "https://api.ejemplo.com/v1/articulos.json?=page7"},
{"rel": "self", "url": "https://api.ejemplo.com/v1/articulos.json"}
]
}
}
"articulos": [
{
"id": 1,
"url": "https://api.ejemplo.com/v1/articulos/1-hola.json",
"titulo": "La innovación en Medellín",
"contenido": "El contenido del articulo",
"tags": [],
"autor": {
"nombre": "Nicolás Hock Isaza",
"url": "https://api.ejemplo.com/v1/autores/323.json"
},
"creado": "Agosto 20, 2013"
},
{
"id": 43,
"url": "https://api.ejemplo.com/v1/articulos/43.json",
"titulo": "Pico y Placa segundo semestre 2013",
"contenido": "El contenido del articulo",
"tags": [
{"nombre": "pico y placa", "url": "https://api.ejemplo.com/v1/etiquetas/24.json"}
],
"autor": {
"nombre": "Alejandra Montoya",
"url": "https://api.ejemplo.com/v1/autores/1.json"
},
"creado": "Juli 10, 2013"
}
]
}
GET /v1/articulos/1-hola.json
{
"metadata": {
"links":{
[
{"rel": "self", "url": "https://api.ejemplo.com/v1/articulos/1-hola.json"}
]
}
}
"articulo":{
"id": 1,
"url": "https://api.ejemplo.com/v1/articulos/1-hola.json",
"titulo": "La innovación en Medellín",
"contenido": "El contenido del articulo",
"tags": [],
"autor": {
"nombre": "Nicolás Hock Isaza",
"url": "https://api.ejemplo.com/v1/autores/323.json"
},
"creado": "Agosto 20, 2013"
}
}
POST /v1/articulos.json
{
"titulo": "Un nuevo artículo",
"contenido": "El contenido del nuevo articulo",
"autor": {
"nombre": "Juan Guillermo Lalinde"
}
"tags": [
{"nombre": "innovacion"}, {"nombre": "pico y placa"}
]
}