Lineamientos de Diseño para APIS REST
El siguiente documento tiene como objetivo definir lineamientos y estándares para el diseño de
APIS REST en Sunbelt con el fin de centralizar la forma de diseñar e implementar servicios internos
de la compañía y para clientes.
Conceptos básicos:
REST es un estilo arquitectónico de software que define un conjunto de restricciones que se
utilizarán para crear servicios web. Los servicios web que se ajustan al estilo arquitectónico REST,
llamados servicios web RESTful (RWS), proporcionan interoperabilidad entre sistemas informáticos
en Internet.
Los servicios web RESTful permiten a los sistemas solicitantes acceder y manipular representaciones
textuales de recursos web mediante el uso de un conjunto uniforme y predefinido de operaciones
sin estado.
API es un conjunto de definiciones y protocolos que se utiliza para desarrollar e integrar el software
de las aplicaciones. API significa interfaz de programación de aplicaciones.
Las API permiten que sus productos y servicios se comuniquen con otros, sin necesidad de saber
cómo están implementados. Esto simplifica el desarrollo de las aplicaciones y permite ahorrar
tiempo y dinero. Las API le otorgan flexibilidad; simplifican el diseño, la administración y el uso de
las aplicaciones, y proporcionan oportunidades de innovación, lo cual es ideal al momento de
diseñar herramientas y productos nuevos (o de gestionar los actuales).
A veces, las API se consideran como contratos, con documentación que representa un acuerdo entre
las partes: si una de las partes envía una solicitud remota con cierta estructura en particular, esa
misma estructura determinará cómo responderá el software de la otra parte.
URI es una cadena de caracteres que identifica los recursos de una red de forma unívoca. La
diferencia respecto a un localizador de recursos uniforme (URL) es que estos últimos hacen
referencia a recursos que, de forma general, pueden variar en el tiempo.
Diseño de URI para REST API
Las API REST usan identificadores uniformes de recursos (URI - Uniform Resource Identifiers) para
direccionar recursos. Actualmente, los diseños de URI van desde recursos simples que comunican
claramente el modelo de la API como:
http://api.ejemplo.com/libros/gabriel-garcia-marquez/la-hojarasca
hasta aquellos que son mucho más difíciles de entender para las personas, como:
http://api.ejemplo.com/68dd0-a9d3-11e0-9f1c-0800200c9a66
Los diseños de API REST deben tener URI que transmitan un modelo de recurso a sus potenciales
desarrolladores de clientes, teniendo en cuenta la siguiente sintaxis:
URI = esquema ": //" autoridad "/" ruta ["?" consulta] [fragmento "#"]
Regla #1
No incluir separador de barra diagonal (/) al final de una URI.
Esta es una de las reglas más importantes a seguir, como el último personaje dentro de la ruta de
un URI, una barra diagonal (/) no agrega valor semántico y puede causar confusión.
Las API REST no deben esperar una barra diagonal final y no deben incluirlas en los enlaces que
proporcionan a los clientes.
Muchos marcos y componentes web tratarán los siguientes dos URI por igual:
http://api.dibujo.com/formas/
http://api.dibujo.com/formas
Sin embargo, cada personaje dentro de un URI cuenta para la identidad única de un recurso.
Dos URI diferentes se asignan a dos recursos diferentes. Si los URI difieren, también lo hacen los
recursos, y viceversa. Por lo tanto, una API REST debe generar y comunicar URI limpios y debe ser
intolerante con los intentos de cualquier cliente de identificar un recurso de manera imprecisa.
Nota: Las API más indulgentes pueden redirigir a los clientes a URI sin una barra diagonal (también
pueden devolver el 301 - "Movido permanentemente" que se utiliza para reubicar recursos ").
Regla #2
Usar el separador de barra diagonal (/) para indicar una relación jerárquica.
El carácter de barra diagonal (/) se usa en la porción de ruta del URI para indicar una relación
jerárquica entre recursos. Por ejemplo:
http://api.dibujo.com/formas/poligonos/cuadrilateros/cuadriculas
Regla #3
Usar guiones (-) para mejorar la legibilidad de los URI.
Para que las personas puedan escanear e interpretar fácilmente sus URI, use el carácter de (-) guion
para mejorar la legibilidad de los nombres en segmentos de ruta larga.
En cualquier lugar donde use un espacio o guion, debe usar un guion en un URI.
Ejemplo:
http://api.blog.com/blogs/pipecode/publicaciones/mi-primer-publicacion
Regla #4
No usar guiones bajos (_) en las URI
Las aplicaciones de visor de texto (navegadores, editores, etc.) a menudo subrayan los URI para
proporcionar una señal visual de que se puede hacer clic.
Dependiendo de la fuente de la aplicación, el carácter de subrayado (_) puede quedar parcialmente
oculto o completamente oculto por este subrayado. Para evitar esta confusión, use guiones (-) en
lugar de guiones bajos.
Regla #5
Usar letras minúsculas en las rutas URI.
Se prefieren las letras minúsculas en las rutas de URI ya que las letras mayúsculas a veces pueden
causar problemas.
El estándar define los URI como sensibles a mayúsculas y minúsculas, excepto para el esquema y
los componentes del host.
Por ejemplo:
1) http://api.ejemplo.com/mi-carpeta/mi-documento
2) HTTP://API.EJEMPLO.COM/mi-carpeta/mi-documento
El URI anterior está bien. La especificación del formato URI (RFC 3986) considera que este URI es
idéntico al URI # 1.
3) http://api.ejemplo.com/Mi-Carpeta/Mi-Documento
Este URI no es lo mismo que los URI 1 y 2, lo que puede causar confusión innecesaria.
Regla #6
Las extensiones de archivo no deben incluirse en los URI.
En la Web, el carácter de punto (.) Se usa comúnmente para separar el nombre de archivo y las
porciones de extensión de un URI.
Una API REST no debe incluir extensiones de archivos en URI para indicar el formato de un
mensaje. En cambio, deben confiar en el tipo de medio, tal como se comunica a través del
encabezado Content-Type, para determinar cómo procesar el contenido del cuerpo.
http://api.college.com/students/3248234/courses/2005/fall.json
http://api.college.com/students/3248234/courses/2005/fall
Las extensiones de archivo no deben usarse para indicar la preferencia de formato.
Se debe alentar a los clientes de API REST a utilizar el mecanismo de selección de formato
proporcionado por HTTP, el encabezado de solicitud Accept.
Nota: Para habilitar enlaces simples y depuración fácil, una API REST puede admitir la selección del
tipo de medio a través de un parámetro de consulta.
Ejemplo: http://api.college.com/students/3248234/courses/2005/fall?format=json
Métodos HTTP
Se deben usar sistemáticamente verbos HTTP para describir qué acciones se realizan en los recursos
y facilitar el trabajo del desarrollador que maneja las operaciones CRUD recurrentes.
Para el diseño de nuestros APIs haremos uso de los siguientes métodos:
GET
El método GET se usa para recuperar información del servidor usando un URI.
Las solicitudes que utilizan GET solo deberían recuperar datos y deben tener otro efecto sobre los
datos, como crear, modificar, etc.
POST
Una solicitud POST se utiliza para enviar datos al servidor, por ejemplo, información del cliente,
carga de archivos, etc.
PUT
Una solicitud PUT se utiliza para actualizar datos o representaciones actuales de una entidad.
DELETE
Una solicitud DELETE se utiliza para eliminar todos los datos o una entidad.
PATCH
Una solicitud PATH se utiliza para actualizar parcialmente datos o representaciones de una
entidad.
Diseño de APIs Pragmáticos
El objetivo es que la API sea fácil de usar, implementar, adaptar y lo suficientemente flexible como
para alimentar nuestras interfaces de usuario.
Requisitos clave para una API
- Debe ser amigable para el desarrollador y ser explorable a través de una barra de direcciones del
navegador
- Debe ser simple, intuitivo y consistente hacer que la adopción no solo sea fácil sino agradable
- Debe proporcionar suficiente flexibilidad para alimentar la mayoría de las interfaces de usuario
- Debe ser eficiente, manteniendo el equilibrio con los otros requisitos.
Una API es la interfaz de usuario de un desarrollador; al igual que cualquier interfaz de usuario, es
importante asegurarse de que la experiencia del usuario se piense cuidadosamente.
Los principios clave de REST implican separar su API en recursos lógicos. Estos recursos se manipulan
utilizando solicitudes HTTP donde como lo mencionamos anteriormente los métodos (GET, POST,
PUT, PATCH, DELETE) tiene un significado específico.
Los recursos deben ser sustantivos y no verbos. Que tengan sentido desde la perspectiva del
consumidor de API. Algunos de los sustantivos serían cupón, usuario y grupo.
Una vez que haya definido sus recursos, debe identificar qué acciones se aplican a ellos y cómo se
asignarían a su API. Los principios RESTFUL proporcionan estrategias para manejar acciones CRUD
utilizando métodos HTTP asignados de la siguiente manera:
GET /cupon recupera una lista de cupones
GET /cupon/12 recupera un cupón especifico
POST /cupon crea un nuevo cupón
PUT /cupon/12 actualiza un cupón especifico
PATCH /cupon/12 actualiza parcialmente un cupón especifico
DELETE /cupon/12 borra un cupón especifico
Lo mejor de REST es que está aprovechando los métodos HTTP existentes para implementar una
funcionalidad significativa en un único punto final (endpoint) /cupon.
No hay convenios de denominación de métodos a seguir y la estructura de URL es limpia y clara.
IMPORTANTE: Los puntos finales o endpoints deben ser singulares
Manejo de Versiones
Siempre manejar versión en los API. El control de versiones ayuda a iterar más rápido y evita que
solicitudes no válidas lleguen a puntos finales (endpoints) que han sido actualizados.
También ayuda a suavizar las transiciones de versiones principales de API, ya que puede continuar
ofreciendo versiones antiguas de API por un período de tiempo.
Nota: Las versiones de api se identifican con un recurso en el URI.
Ejemplo:
GET http://api.libros.com/v1/libros Esto debe recuperar el listado de libros referentes a la versión
1 del api.
Filtrado, Clasificación y Búsquedas
Siempre mantener las URL de recursos base lo más esbeltas posible. Los filtros de resultados
complejos, los requisitos de clasificación y la búsqueda avanzada (cuando se restringe a un solo
tipo de recurso) se pueden implementar fácilmente como parámetros de consulta en la parte
superior de la URL base. A continuación, se especifica como hacerlo:
Filtrado
Usar un parámetro de consulta único para cada campo que implemente el filtrado.
Por ejemplo, al solicitar una lista de cupones desde el punto final (endpoint) /cupon, es posible que
desee limitarlos solo a aquellos en estado abierto. Esto podría lograrse con una solicitud como:
GET /cupon?status=abierto. Aquí, el estado es un parámetro de consulta que implementa un filtro.
Clasificación
Similar al filtrado, se puede usar una clasificación de parámetros genéricos para describir las reglas
de clasificación.
Acomode los requisitos de clasificación complejos permitiendo que el parámetro de clasificación
tome en cuenta una lista de campos separados por comas, cada uno con un posible negativo para
implicar un orden de clasificación descendente. A continuación, se especifica como hacerlo:
GET /cupon?sort=-priority - Recupera una lista de cupones en orden descendente de prioridad
GET /cupon?sort=-priority,created_at - recupera una lista de cupones en orden descendente de
prioridad y ascendentes a su fecha de creación.
Búsqueda
A veces los filtros básicos no son suficientes y se necesita el poder de la búsqueda de texto
completo. Cuando la búsqueda de texto completo se utiliza como un mecanismo para recuperar
instancias de recursos para un tipo específico de recurso, puede exponerse en la API como un
parámetro de consulta en el punto final del recurso. Digamos query. Las consultas de búsqueda
deben pasarse directamente al motor de búsqueda y la salida de la API debe estar en el mismo
formato que un resultado de lista normal.
Combinando estos juntos, podemos construir consultas como:
GET /cupon?sort=-updated_at - Recupera cupones actualizados recientemente
GET /cupon?state=closed&sort=-updated_at - Recupera cupones cerrados recientemente
GET /cupon?query=descuento&state=open&sort=-priority, created_at - Recupera los cupones en
estado abierto de mayor prioridad que mencionan la palabra ‘descuento’
Alias para consultas comunes
Para que la experiencia API sea más agradable para el consumidor promedio, considere empaquetar
conjuntos de condiciones en rutas RESTful de fácil acceso.
Por ejemplo, la consulta anterior de cupones recientemente cerrados se podría empaquetar
como GET /cupon/cerrados
NOTA: hacer esto solo en consultas comunes y recurrentes.
JSON ONLY
Dejaremos atrás XML en las API. Es detallado, es difícil de analizar, es difícil de leer, su modelo de
datos no es compatible con la forma en que la mayoría de los lenguajes de programación modelan
datos y sus ventajas de extensibilidad son irrelevantes cuando las necesidades principales de su
representación de salida son la serialización desde una representación interna.
Errores
Al igual que una página de error HTML muestra un mensaje de error útil para un visitante, una API
debe proporcionar un mensaje de error útil en un formato consumible conocido. La representación
de un error no debe ser diferente a la representación de cualquier recurso, solo con su propio
conjunto de campos.
La API siempre debe devolver códigos de estado HTTP razonables. Los errores de API generalmente
se dividen en 2 tipos: códigos de estado de la serie 400 para problemas del cliente y códigos de
estado de la serie 500 para problemas del servidor. Como mínimo, la API debería estandarizar que
todos los errores de la serie 400 vengan con una representación de error JSON consumible. Si es
posible (es decir, si los equilibradores de carga y los servidores proxy inversos pueden crear cuerpos
de error personalizados), esto debería extenderse a los códigos de estado de la serie 500.
Un cuerpo de error JSON debe proporcionar algunas cosas para el desarrollador: un mensaje de
error útil, un código de error único (que se puede buscar para obtener más detalles en los
documentos) y posiblemente una descripción detallada. La representación de salida JSON para algo
como esto se vería así:
{
"code": Código del error,
"message": "Mensaje amigable del error",
"description" : "Mensaje detallado del error"
}
Los errores de validación para solicitudes PUT, PATCH y POST necesitarán un desglose de
campo. Esto se modela mejor mediante el uso de un código de error de nivel superior fijo para
fallas de validación y proporcionando los errores detallados en un campo de errores adicional, de
esta manera:
{
"code”: 1024,
"message”: "Error de validación",
"errors”: [
{
"code”: 5432,
"field”: "primerNombre",
"message”: "Primer nombre no debe tener caracteres extraños"
},
{
"code”: 5622,
"field”: "password",
"message”: "La contraseña no puede estar vacía"
}
]
}
Códigos de estado HTTP
HTTP define un montón de códigos de estado significativos que se pueden devolver desde su API.
Se pueden aprovechar para ayudar a los consumidores de API a encaminar sus respuestas en
consecuencia. A continuación, los estados que debemos usar como mínimo:
200 OK
Respuesta a un GET, POST, PATCH o DELETE exitosamente. También se puede usar para una POST
que no da como resultado una creación.
201 CREATED
Respuesta a una POST que resulta en una creación. Se puede combinar con un encabezado de
ubicación que apunte a la ubicación del nuevo recurso
204 NO CONTENT
respuesta a una solicitud exitosa que no devolverá un cuerpo (como una solicitud DELETE)
304 NOT MODIFIED
Se utiliza cuando los encabezados de almacenamiento en caché HTTP se están utilizando.
400 BAD REQUEST
Respuesta a una solicitud que tiene un formato incorrecto, puede ser en su cuerpo o parámetros.
401 UNAUTHORIZED
Cuando no se proporcionan detalles de autenticación válidos. También es útil para activar una
ventana emergente de autenticación si la API se usa desde un navegador
403 FORBIDDEN
cuando la autenticación se realizó correctamente pero el usuario autenticado no tiene acceso al
recurso
404 NOT FOUND
Cuando se solicita un recurso inexistente
405 METHOD NOT ALLOWED
Cuando se solicita un método HTTP que no está permitido para el usuario autenticado
410 GONE
Indica que el recurso en este punto final ya no está disponible. Útil como respuesta general para
versiones antiguas de API
415 UNSUPPORTED MEDIA TYPE
Si se proporcionó un tipo de contenido incorrecto como parte de la solicitud
Asegurando APIS REST
Nuestros APIS Deben ser seguros, tanto para consumos internos como consumos externos (nuestros
clientes) para eso se sugiere que los APIS estén asegurados con mecanismos de
Autenticación/Autorización Oauth/Oauth2 o Mínimamente un mecanismo de Autenticación Básica
haciendo uso de JWT y manejo de sesiones.