You are on page 1of 13

Tu modelo de datos ha empezado a estabilizarse y es el momento de crear una API pblica para tu

aplicacin web. Te das cuenta de que es difcil hacer cambios significativos a tu API una vez que fue
liberada, quieres lo mejor y lo antes posible. Ahora, en internet no escasean opiniones sobre diseo de
APIs. Pero, debido a que no hay un standard adoptado popularmente que funcione en todos los casos, te
quedas con un manojo de opciones: Qu formatos deberas aceptar? Cmo deberas autenticar?
Debera tu API ser versionada?
Diseando una API para SupportFu (una alternativa para Zendesk), intent encontrar respuestas
pragmticas a estas preguntas. Mi objetivo para la API de SupportFu es que sea fcil de usar, facil de
adoptar y lo suficientemente flexible para implementarla en nuestras propias interfaces de usuario.

TL,DR

1.

Usa SSL en todos lados, sin excepciones

2.

Una API es tan buena como lo es su documentacin por lo tanto realiza una buena
documentacin

3.

Versiona a travs de la URL, no de los encabezados

4.

Usa parmetros de consulta para filtros avanzados, ordenamiento y bsqueda

5.

Provee una forma de limitar cules campos son devueltos desde la API

6.

Devuelve algo til de las peticiones POST, PATCH & PUT

7.

HATEOAS todava no es muy prctico

8.

Usa JSON donde sea posible, XML slo si tienes la obligacin

9.

Deberas usar camelCase con JSON, pero snake_case es un 20% ms fcil de leer

10. Usa Pretty Print por defecto y asegura que gzip est soportado
11. No uses respuestas encapsuladas por defecto
12. Considera usar JSON para cuerpos de peticiones POST, PUT y PATCH
13. Pagina usando encabezados Link
14. Provee una forma de cargar automticamente representaciones de datos relacionados al recurso
solicitado
15. Provee una forma de sobreescribir el mtodo HTTP
16. Provee encabezados de respuesta tiles para controles de trfico (rate limiting)
17. Usa autenticacin basada en tokens, transportado en OAuth2 donde se necesite delegacin
18. Incluir encabezados de respuesta que faciliten el cach
19. Define un error de carga til (payload) que sea consumible

20. Utilizar efectivamente los cdigos de error HTTP


1. Requisitos fundamentales para la API
Muchas de las opiniones sobre diseo de API que aparecen en la web son discusiones acadmicas en
torno a interpretaciones subjetivas de las normas difusas en lugar de lo que tiene sentido en el mundo real.
Mi objetivo con este artculo es describir las mejores prcticas para una API pragmtica diseada para
aplicaciones web de hoy en da. No hago ningn intento de satisfacer un standard si no parece viable.
Para ayudar a guiar el proceso de toma de decisiones, he escrito algunos de los requisitos que la API debe
cubrir:

Debera utilizar estndares web donde tengan sentido

Debera ser amigable para el desarrollador y ser explorable mediante una barra de direcciones
del navegador

Debera ser sencilla, intuitiva y consistente para que la adopcin no slo sea fcil, sino tambin
agradable

Debera proporcionar suficiente flexibilidad para potenciar mayoritariamente la UI SupportFu

Debera ser eficiente, manteniendo el equilibrio con los dems requisitos

Una API es una interfaz de usuario (UI) para un desarrollador al igual que cualquier UI, es importante
asegurar que la experiencia del usuario est pensada cuidadosamente

2. Usa acciones y URLs RESTful


Si hay una cosa que ha ganado amplia adopcin, son los principios REST. Estos fueron presentados por
primera vez por Roy Felding en el Captulo 5 de su disertacin sobre arquitecturas de software ubicadas
en redes de trabajo.
Los fundamentales principios de REST se basan en separar tu API en recursos lgicos. Estos recursos son
manipulados usando peticiones HTTP donde el mtodo (GET, POST, PUT, PATCH, DELETE) tienen un
significado especfico.
Pero qu puede hacer un recurso? Bueno, estos deberan ser sustantivos (no verbos!) que tengan
sentido desde una perspectiva del consumidor de la API. Aunque tus modelos internos pueden mapear
cuidadosamente con los recursos, no es necesario que sea un mapeo uno-a-uno. La clave es no filtrarse
ningn detalle irrelevante de implementacin. Por ejemplo, algunos de los sustantivos de SupportFu
podran ser ticket, usuario y grupo.
Una vez que tienes tus recursos definidos, necesitas identificar qu acciones aplican a ellos y cmo
deberan relacionarse con tu API. Los principios REST proveen estrategias para manejar acciones CRUD
usando mtodos HTTP relacionados de la siguiente forma:

GET /tickets- Devuelve una lista de tickets

GET /tickets/12- Devuelve un ticket especfico

POST /tickets- Crea un nuevo ticket

PUT /tickets/12- Actualiza el ticket #12

PATCH /tickets/12- Actualiza parcialmente el ticket #12

DELETE /tickets/12- Elimina el ticket #12

La grandeza de REST es que estas impulsando mtodos HTTP existentes a implementar funcionalidades
importantes en slo un simple endpoint /tickets. No hay convencin de nombres de mtodos para seguir y
la estructura URL es limpia y clara.
El nombre del Endpoint debera ser singular o plural? La regla mantenlo-simple (keep-it-simple)
aplica aqu. Si bien tu gramtica interna te dir que est mal describir una instancia nica de un recurso
utilizando el plural, la respuesta pragmtica es mantener el formato de la URL consistente y siempre usar
plural. No tener que lidiar con plurales irregulares (person/people, goose/geese) hace ms simple la vida
del consumidor de la API y es ms sencillo para el proveedor de la API implementarla (como los ms
modernos frameworks manejarn nativamente /tickets y /tickets/12 bajo un controlador comun).
Pero cmo lidiar con las relaciones? Si una relacin puede existir con un slo recurso, los principios
REST proveen una gua til. Veamos esto con un ejemplo. Un ticket en SupportFu consiste en un nmero
de mensajes. Estos mensajes pueden ser lgicamente mapeados al endpoint /tickets de la siguiente forma:

GET /tickets/12/messages - Devuelve una lista de mensajes para el ticket #12

GET /tickets/12/messages/5 - Devuelve el mensaje #5 para el ticket #12

POST /tickets/12/messages - Crea un nuevo mensaje en el ticket #12

PUT /tickets/12/messages/5 Actualiza el mensaje #5 para el ticket #12

PATCH /tickets/12/messages/5 - Actualiza parcialmente el mensaje #5 para el ticket #12

DELETE /tickets/12/messages/5 - Borra el mensaje #5 para el ticket #12

Alternativamente, si una relacin puede existir independientemente del recurso, tiene sentido incluir slo
un identificador en la representacin de la salida del recurso. El consumidor de la API debera entonces
tener que acertar al endpoint de la relacin. Sin embargo, si la relacin es comunmente requerida junto
con el recurso, la API podra ofrecer funcionalidad para automticamente incluir la representacin de la
relacin y evitar el segundo impacto en la API.
Qu ocurre con las acciones que no corresponden a las operaciones CRUD?
Aqu es donde las cosas pueden confundirse. Hay un nmero de enfoques:
1.

Reestructura la accin para que aparezca como un campo de un recurso. Esto funciona si la
accin no toma parmetros. Por ejemplo, un accin activate puede ser asignada a un campo
booleano activated y actualizado va PATCH al recurso.

2.

Tratalo como un sub-recurso con principios REST. Por ejemplo, la API de GitHub te permite
star a gist(marcar como importante) con PUT /gists/:id/star y unstar (desmarcar) con
DELETE /gists/:id/star.

3.

A veces realmente no tienes forma de mapear la accin a una estructura REST apropiada. Por
ejemplo, una bsqueda multi-recurso no tiene sentido ser asignada a un endpoint de un recurso
especfico. En este caso, /search podra tener ms sentido incluso si no es un sustantivo. Esto
est BIEN slo realiza lo que sea correcto desde la perspectiva del consumidor de la API y
asegrate de que est claramente documentado para evitar confusiones.

3. SSL en todos lados todo el tiempo


Usa siempre SSL. Sin excepciones. Hoy, tus APIs web pueden ser accedidas desde cualquier lado donde
haya internet (como libreras, cafeteras, aeropuertos, entre otros). No todos son seguros. Muchos no
encriptan las comunicaciones, permitiendo facilmente ser espiados o falsificados si son interceptadas las
credenciales de autenticacin.

Otra ventaja de usar siempre SSL es que garantiza que las comunicaciones encriptadas simplifiquen los
esfuerzos de autenticacin puedes salir simplemente con los tokens de acceso en vez de tener que firmar
cada peticin a la API.
Hay que tener cuidado con los accesos no-SSL a las URLs de la API. NO las redirecciones a sus
homlogas SSL. Es recomendable que lances un error. La ltima cosa que quieres para tus clientes
pobremente configurados es enviar peticiones a un endpoint sin encriptar, slo para ser redireccionados
silenciosamente al verdadero endpoint encriptado.
4. Documentacin
Una API es buena tanto como lo sea su documentacin. Los docs deberan ser fciles de encontrar y de
acceso pblico. Muchos desarrolladores revisarn la documentacin antes de realizar cualquier esfuerzo
para integrarla. Cuando los docs estn escondidos dentro de un archivo PDF o estn permitido slo para
usuarios identificados, no son entonces slo difciles de encontrar sino que tambin dificultan la
bsqueda.
Los documentos deberan mostrar ejemplos de ciclos completos de peticin/respuesta. Preferentemente,
las peticiones deberan poder ser pegadas tanto los hipervnculos deberan poder ser pegados en un
navegador como los ejemplos de cdigo deberan poder ser pegados en una consola. GitHub y Strip hacen
un muy buen trabajo en este aspecto.
Una vez que liberes una API pblica, te comprometes a no romper cosas sin previo aviso. La
documentacin debe incluir informacin y detalles sobre futuras actualizaciones a la API que sean
visibles al exterior. Las actualizaciones deben ser entregadas a travs de un blog (es decir, una lista de
cambios) o una lista de correo (preferiblemente ambos).
5. Versionado
Siempre versiona tu API. El versionado te ayuda a iterar ms rpido y evitar peticiones invlidas desde
endpoints actualizados. Adems te ayuda a resolver cualquier transicin importante de versin de la API
mientras continas ofreciendo viejas versiones de la API por un perodo de tiempo.
Hay opiniones cruzadas respecto si la versin de la API debera ser incluida en la URL o en el
encabezado. Acadmicamente hablando, debera probablemente estar en el encabezado. Sin embargo, la
versin necesita estar en la URL para asegurar la posibilidad de explorar en el navegador los recursos a
travs de las versiones (recuerda los requerimientos de la API especificados al inicio del artculo).
Soy un gran fantico del alcance que Stripe ha tomado respecto al versionado de la API - la URL tiene un
nmero de versin principal (v1), pero la API tiene las sub-versiones basadas en fechas que pueden ser
elegidas mediante un encabezado de peticin HTTP personalizado. En este caso, la versin principal
proporciona la estabilidad estructural de la API en su conjunto, mientras que las sub-versiones
representan cambios ms pequeos (campos inhabilitados, cambios en el endpoint, etc).
Una API nunca va a ser completamente estable. El cambio es inevitable. Lo importante es cmo se
gestiona el cambio. Anuncios de fechas y planificaciones bien documentados puede ser una buena
prctica para muchas APIs. Todo se reduce a lo que es razonable teniendo en cuenta la industria y los
posibles consumidores de la API.

6. Filtrado, ordenacin y bsqueda en los resultados


Lo mejor es mantener la URL base de recursos tan simple como sea posible. Filtros de resultados
complejos, requisitos de ordenamiento y bsqueda avanzada (cuando se limita a un solo tipo de recurso)
pueden ser implementados fcilmente como parmetros de consulta en la parte superior de la URL base.
Veamos esto en ms detalle:
Filtrado: Usa un nico parmetro de consulta por cada campo que implemente el filtro. Por ejemplo,
cuando se pide una lista de tickets del endpoint /tickets, podras querer limitarla a slo los que estn en
estado abierto. Esto puede ser logrado con una peticin como GET /tickets?state=open. En este caso,
state es el parmetro de la consulta que implementa el filtro.
Ordenacin: Similar al filtrado, un parmetro genrico sort puede ser usado para describir las reglas de
ordenamiento. Organiza los requerimientos de ordenamiento complejos permitiendo que el parmetro de
ordenacin sea tomado de una lista de campos separados por coma, cada uno con un posible negativo
unario para implicar orden descendiente. Veamos algunos ejemplos:

GET /tickets?sort=-priority Devuelve una lista de tickets en orden de prioridad descendiente

GET /tickets?sort=-priority,created_at - Devuelve una lista de tickets en orden de prioridad


descendiente. Con una prioridad especfica, los tickets ms viejos son ordenados primero.

Bsqueda: A veces los filtros bsicos no son suficientes y se necesita la posibilidad de realizar una
bsqueda completa sobre el texto. Tal vez ya ests usando ElasticSearch u otra bsqueda basada en la
tecnologa Lucene. Cuando una bsqueda completa sobre el texto es usada como un mecanismo de
devolucin de instancias de recurso para un tipo de recurso especfico, puede ser expuesto en la API como
un parmetro de consulta al endpoint del recurso. Digamos q. Las consultas de bsqueda deberan ser
pasadas directamente al motor de bsqueda y la salida de la API deberan estar en el mismo formato que
un lista de resultado normal.
Combinando todo esto, podemos construir consultas como:

GET /tickets?sort=-updated_at Devuelve los tickets recientemente actualizados

GET /tickets?state=closed&sort=-updated_at - Devuelve los tickets recientemente cerrados

GET /tickets?q=return&state=open&sort=-priority,created_at Devuelve el ticket abierto de


mayor prioridad que menciona la palabra return

Alias para las consultas comunes


Para hacer que la experiencia con la API sea ms agradable para el consumidor promedio, considera
empaquetar sets de condiciones dentro de una ruta REST facilmente accesible. Por ejemplo, la consulta
de tickets cerrados recientemente puede ser empaquetada como GET /tickets/recently_closed.
7. Limitando los campos que son devueltos por la API
El consumidor de la API no siempre necesita la representacin completa de un recurso. La habilidad de
seleccionar y elegir los campos devueltos permite el doble beneficio de dejar que el consumidor de la API
minimice el trfico de red y acelere su propio uso de la API.
Usa el parmetro de consulta fields que tome una lista de campos separados con coma. Por ejemplo, la
siguiente peticin debera traer slo la informacin suficiente para mostrar una lista ordenada de tickets
abiertos:
GET /tickets?fields=id,subject,customer_name,updated_at&state=open&sort=-updated_at
8. Update & Creation deberan devolver una representacin de un recurso
Una llamada PUT, POST o PATCH puede hacer modificaciones a los campos del recurso subyacente que
no fueron parte de los parmetros provistos (por ejemplo: los campos timestamp created_at o
updated_at ). Para evitarle al consumidor de la API tener que consultar nuevamente a la API por un
recurso actualizado, agrega el retorno de la actualizacin (o creacin) como parte de la respuesta.
En el caso de un POST que sea un resultado de una creacin, usa el cdigo de status HTTP 201 e incluye
un encabezado Location que apunte a la URL del nuevo recurso.
9. Deberas HATEOAS?
Hay muchas opiniones variadas sobre si el consumidor de la API debera crear hipervnculos o si los
hipervnculos deberan ser provistos por la API. Los principios de diseo RESTful especifican
HATEOAS, el cual aproximadamente declara que esa interaccin con un endpoit debera definirse en la
metadata que viene con la respuesta, y no basada en informacin que va por fuera de la banda (out-ofband).
A pesar de que la web generalmente trabaja con los principios HATEOAS (ej, cuando vamos a una
portada y seguimos hipervnculos basados en lo que vemos en la pgina), no creo que estemos listos para
HATEOAS en la API todava. Cuando navegamos en un sitio, las decisiones sobre qu hipervnculos van

a ser clickeados se hacen durante la ejecucin. Sin embargo, con una API, las decisiones como qu
peticiones van a ser enviadas son tomadas cuando el cdigo de integracin de la API es escrito, no en
tiempo de ejecucin. Podran las decisiones ser aplazadas al tiempo de ejecucin? Seguro, de todas
maneras, no hay mucho que ganar bajando esa ruta al cdigo ya que el cdigo no estara disponible para
manejar cambios significantes en la API sin romperse. Esto significa que HATEOAS es prometedor pero
no est listo para ser protagonista todava. Algn esfuerzo ms tiene que ser realizado para definir los
estndars y herramientas al rededor de estos principios para que su potencial sea completamente
aprovechado.
Por ahora es mejor asumir que el usuario tiene acceso a la documentacin e incluir los identificadores de
recursos en la respuesta, la cual el consumidor de la API usar cuando crea hipervnculos. Hay un par de
ventajas en utilizar los identificadores los datos que viajan sobre la red son minimizados y los datos
almacenados por los consumidores de la API tambin son minimizados (ya que son guardados los
identificadores cortos, en vez de las URLs que contienen los identificadores).
Adems, dado que este post es partidario de incluir los nmeros de versin en la URL, tiene ms sentido a
largo plazo para el consumidor de la API almacenar los identificadores y no las URLs. Despus de todo,
el identificador es estable versin por versin pero la URL que representa no lo es!
10. Slo respuestas JSON
Es tiempo de dejar XML atras en las APIs. Es verborrgico, es difcil de parsear, dificil de leer, su modelo
de datos es incompatible con la mayora de los modelos de datos de los lenguajes de programacin y sus
ventajas son irrelevantes cuando tus necesidades primarias de respuesta son serializaciones de una
representacin de datos interna.
No voy a poner mucho esfuerzo en explicar las razones de lo dicho arriba si se puede ver cmo otros
(Youtube, Twitter & Box) ya han comenzado el xodo XML.
Simplemente te dejar que veas las grficas de Google Trends (XML API vs JSON API) para que
medites:

No obstante, si tu base de clientes consiste en un gran nmero de clientes empresariales, puedes tener que
dar soporte XML de todas maneras. Si debes hacerlo, te surgir una nueva pregunta:
Debera cambiar el tipo del contenido basado en encabezados Accept o basado en la URL? Para
garantizar la explorabilidad del navegador, debera basarse en la URL. La opcin ms razonable debera
ser agregar una extensin .xml o .json al endpoint de la URL .
11. snake_case vs camelCase para el nombre de los campos
Si ests usando JSON (JavaScript Object Notation) como tu principal formato de representacin, la forma
correcta de hacer las cosas es seguir la convencin de nombres de JavaScript y esto sinifica
camelCase para el nombre de los campos! Si entonces optas por el camino de construir librerias cliente en
varios lenguajes, lo mejor es usar la convencin de nombres correspondiente al idioma camelCase para
C# y Java, snake_case para python y ruby.

Para pensar: Siempre sent que snake_case es ms fcil para leer que la convencin camelCase de
JavaScript. Pero no tena ninguna evidencia para respaldar esta sensacin, hasta ahora. Basado en un
estudio visual sobre camelCase y snake_case (PDF) del 2010, snake_case es un 20% ms facil de leer
que camelCase! Este impacto en legibilidad puede afectar la explorabilidad de la API y los ejemplos de
la documentacin.
Muchas JSON APIs populares usan snake_case. Sospecho que esto se debe a la serializacin de libreras
que siguen las convenciones de nombres de los lenguajes subyacentes que utilizan. Tal vez necesitamos
tener libreras de serializacin JSON que manejen las transformaciones de convenciones de nombres.
12. Pretty print por default y asegura que gzip sea soportado
Una API que provee salida con compresin de espacios en blanco no es muy divertida de ver desde un
navegador. Aunque algn tipo de parmetro de consulta (como ?pretty=true) puede ser provisto para
activar pretty printing, una API que utiliza pretty print por default es mucho ms accesible. El costo de
transferencia de datos extra es insignificante, especialmente cuando lo comparas con el costo de no
implementar gzip.
Considera algunos casos de uso: Qu pasa si un consumidor de la API est debuggeando y en su cdigo
imprime los datos recibidos de la API? Sern legibles por default. O si el consumidor graba en la URL
el cdigo que fue generando y lo interpreta directamente desde el navegador Ser legible por default.
stos son pequeos detalles. Pequeos detalles que hacen a una API agradable de usar!
Pero, qu pasa con toda la transferencia extra de datos?
Veamos esto con un ejemplo del mundo real. He bajado un poco de datos de la API de GitHub, la cual usa
pretty print por default. Tambin estuve haciendo algunas comparaciones con gzip:
$ curl https://api.github.com/users/veesahni > with-whitespace.txt
$ ruby -r json -e 'puts JSON JSON.parse(STDIN.read)' < with-whitespace.txt > without-whitespace.txt
$ gzip -c with-whitespace.txt > with-whitespace.txt.gz
$ gzip -c without-whitespace.txt > without-whitespace.txt.gz
Los archivos de salida tienen los siguientes tamaos:

without-whitespace.txt 1252 bytes

with-whitespace.txt 1369 bytes

without-whitespace.txt.gz 496 bytes

with-whitespace.txt.gz 509 bytes

En este ejemplo, el caracter en blanco increment el tamao de la salida en un 8.5% cuando gzip no entr
en juego y un 2.6% cuando utilizamos gzip. Por otro lado, el acto de comprimir con gzip en s mismo
provee un 60% de ahorro de ancho de banda. Debido a que el costo del pretty print es relativamente
pequeo, es mejor utilizar pretty print por default y asegurar que la compresin con gzip est soportada.
Para enfatizar este punto, Twitter descubri que hay un 80% de ahorro (en algunos casos) cuando habilita
la compresin gzip en su API Streaming. Stack Exchange fue ms lejos, nunca devuelve una respuesta
que no est comprimida!
13. No uses un envoltorio por default, pero posibilitalo cuando sea necesario
Muchas APIs empaquetan sus respuestas en envoltorios como este:
{
"data" : {
"id" : 123,

"name" : "John"
}
}
Hay un par de justificaciones para hacer esto facilita incluir metadata adicional o informacin de
paginacin, algunos clientes REST no permiten fcil acceso a los encabezados HTTP y las peticiones
JSONP no tienen acceso a sus encabezados. Sin embargo con standards que estn siendo rpidamente
adoptados como CORS y Link header from RFC5988, empaquetar se est volviendo innecesario.
Podemos profundizar a futuro la API mantenindola sin empaquetamiento por default y empaquetando
slo en casos excepcionales.
Cmo debera usarse un envoltorio en casos excepcionales?
Hay 2 situaciones donde un envoltorio es realmente necesario si la API necesita soportar peticiones
cross domain sobre JSONP o si el cliente es incapaz de trabajar con encabezados HTTP.
Las peticiones JSONP vienen con un parmetro adicional de consulta (usualmente llamado callback o
jsonp) representando el nombre de la funcin callback. Si este parmetro est presente, la API debera
cambiarse a un modo completo de empaquetamiento donde siempre responda con un cdigo de status
HTTP 200 y pase el cdigo de status real dentro de la respuesta JSON. Cualquier encabezado HTTP
adicional que debera pasar a travs de la respuesta debera ser mapeado a los campos JSON, como se ve
a continuacin:
callback_function({
status_code: 200,
next_page: "https://..",
response: {
... actual JSON response body ...
}
})
De forma similar, para soportar clientes con HTTP limitado, habilita un parmetro especial de consulta ?
envelope=true, el cual debera disparar un empaquetamiento full (sin la funcin callback JSONP).
14. Cuerpos HTML POST, PUT & PATCH codificados en JSON
Si ests siguiendo el objetivo de este artculo, entonces has adoptado JSON para todas las salidas de la
API. Ahora consideremos JSON para la entrada de la API.
Muchas APIs usan URL cifradas en sus cuerpos de las peticiones de la API. El cifrado de URL es
exactamente lo que suena los cuerpos de la peticin donde los pares clave-valor estn cifrados usando
las mismas convenciones que uno usara para cifrar datos en los parmetros de consulta de URL. Esto es
simple, ampliamente soportado y deja el trabajo hecho.
Sin embargo, el cifrado de URL tiene algunos inconvenientes que lo hacen problemtico. No tiene el
concepto de tipos de dato. Esto obliga a la API a interpretar cadenas de caracteres y transformarlas en
tipos numricos (por ej integer) o booleanos. Adems, no tiene un concepto real de estructura jerrquica.
Aunque hay algunas convenciones que pueden construir estructuras que no siguen el par clave-valor
(como agregar [] a una clave para representar un arreglo), esto no tiene comparacin con la estructura
nativa jerrquica de JSON.
Si la API es simple, cifrar la URL puede ser suficiente. Sin embargo, APIs complejas deberan apegarse a
JSON para sus entradas a la API. De cualquier manera, elige una y se consistente en toda la API.
Una API que acepta peticiones POST, PUT y PATCH con cifrado JSON debera tambin requerir en el
encabezado Content-Type seteado con application/json o lanzar un cdigo de status HTTP: 415
Unsopported Media Type.
15. Paginacin
Las APIs con preferencia envelope (envoltorio) tpicamente incluyen los datos de paginacin dentro del
mismo envoltorio. Y no los culpo hasta hace poco, no haba mejores opciones. La forma correcta de
incluir los detalles de paginacin hoy en da es utilizando el encabezado Link introducido por RFC 5988.

Una API que usa el encabezado Link puede devolver un set de hipervnculos listos para que el
consumidor de la API no tenga que construir los hipervnculos por su propia cuenta. Esto es
especialmente importante cuando la paginacin est basada en el cursor. Aqu hay un ejemplo de un
encabezado Link utilizado correctamente, obtenido de la documentacin de GitHub:
Link: <https://api.github.com/user/repos?page=3&per_page=100>; rel="next",
<https://api.github.com/user/repos?page=50&per_page=100>; rel="last"
Pero esto no es una solucin completa para muchas APIs que quieren devolver informacin adicional de
paginacin, por ejemplo el conteo del total de resultados disponibles. Una API que requiere enviar un
contador puede usar un encabezado HTTP personalizado como X-Total-Count.
16. Representaciones de recursos relacionados a los datos solicitados mediante carga automtica
Hay muchos casos donde un consumidor de la API necesita cargar datos relacionados (o referenciados)
con el recurso que se est solicitando. En vez de pedir que el consumidor haga una solicitud a la API
reiteradas veces por esta informacin, sera mucho ms eficiente permitir que los datos relacionados sean
devueltos y cargados a travs del recurso original en demanda.
De todos modos, como esto va contra algunos principios RESTful, podemos minimizar nuestras
desviaciones haciendo entonces el parmetro de consulta embed (o expand).
En este caso, embed podra ser una lista separada por comas de campos a ser embebidos. La notacin con
punto puede ser usada para referir sub-campos. Por ejemplo:
GET /ticket/12?embed=customer.name,assigned_user
Esto debera devolver un ticket con detalles adicionales embebidos, como:
{
"id" : 12,
"subject" : "I have a question!",
"summary" : "Hi, ....",
"customer" : {
"name" : "Bob"
},
assigned_user: {
"id" : 42,
"name" : "Jim",
}
}
Por supuesto, la habilidad de implementar algo as realmente depende de la complejidad interna. Este tipo
de embebido puede facilmente resultar en un problema de N+1 select.
17. Sobreescribiendo el mtodo HTTP
Algunos clientes HTTP pueden trabajar solo con peticiones simples GET y POST. Para mejorar la
accesibilidad a estos clientes limitados, la API necesita proveer una forma de sobreescribir el mtodo
HTTP.
Aunque no hay ningn estandard fuerte aqu, la convencin popular es aceptar un encabezado de peticin
X-HTTP-Method-Override con un valor de cadena que contenga PUT, PATCH o DELETE.
Nota que sobreescribir el encabezado debera ser aceptado en peticiones POST. Las peticiones GET
nunca deberan cambiar datos en el servidor!

18. Limitacin de trfico por ratio (Rate limiting)


Para prevenir abusos, una prctica estandard es agregar algn tipo de lmite de trfico a la API. RFC 6585
introduce el cdigo de status HTTP 429 Too Many Requests para controlar esto.
Sin embargo, puede ser muy til notificar al consumidor de sus lmites antes de que se encuentre con
ellos. Este es un rea en la que actualmente faltan los standards pero existe una cantidad de convenciones
populares usando encabezados de respuesta HTTP.
Minimamente, incluye los siguientes encabezados (usando las convenciones de nombres de Twitter ya
que los encabezados tipicamente no tienen capitalizacion de las palabras del medio):

X-Rate-Limit-Limit El numero de peticiones permitidas en el perodo actual

X-Rate-Limit-Remaining El nmero de peticiones que faltan en el perodo actual

X-Rate-Limit-Reset El nmero de segundos restantes en el perodo actual

Por qu se usa el nmero de segundos restantes en vez de un time stamp para X-Rate-LimitReset?
Un timestamp contiene una cantidad de informacin til pero innecesaria como la fecha y probablemente
el time-zone. Un consumidor de la API realmente quiere saber cundo puede enviar la peticin
nuevamente, y el nmero de segundos responde a esta pregunta con el mnimo procesamiento adicional al
final. Adems escapa a problemas relacionados con desvos de reloj.
Algunas APIs usan un timestamp de UNIX (segundos desde la fecha standard 1/1/1970) para X-RateLimit-Reset. No hagas lo mismo!
Por qu es una mala prctica usar el timestamp UNIX para X-Rate-Limit-Reset?
La spec de HTTP ya especifica el uso del formato de fecha RFC 1123 (actualmente usado en los
encabezados HTTP Date, If-Modified-Since y Last-Modified). Si furamos a especificar un nuevo
encabezado HTTP que tome un timestamp de algn tipo, debera seguir las convenciones RFC 1123 en
vez de usar timestamps UNIX.
19. Autenticacin
Una API RESTful debera ser stateless (sin estado). Esto significa que la peticin de autenticacin no
debera depender de cookies o sesiones. En lugar de ello, cada peticin debera venir con algn tipo de
credencial de autorizacin.
Siempre que se use SSL, las credenciales de autenticacin pueden ser simplificadas a un token de acceso
generado de forma aleatoria, que es entregado en el campo de nombre de usuario de HTTP Basic Auth.
Lo grandioso de esto es que es completamente navegable con un explorador ste simplemente abrira un
popup pidindote que ingreses las credenciales si recibe un cdigo de status 401 Unauthorized desde el
servidor.
De todos modos, este mtodo de autenticacin token-over-basic-auth (token sobre autenticacin basica)
es slo aceptable en los casos en que sea prctico tener la posibilidad de que el usuario copie un token de
una interface de administracin del entorno del consumidor de la API.
En los casos donde no sea posible, OAuth 2 debera ser usado para facilitar la transferencia del token
seguro a terceros. OAuth 2 usa tokens Bearer y adems depende de SSL para su encriptacin de
transporte subyacente.
Una API que necesita soporte JSONP necesitar un tercer mtodo de autenticacin, ya que las peticiones
JSONP no pueden enviar credenciales HTTP Basic Auth ni Bearer tokens. En este caso, puede utilizarse
un parmetro especial de consulta access_token. Nota: hay un problema de seguridad inherente si se

usa un parametro de consulta para el token ya que la mayora de los servidores web almacenan los
parmetros de consulta en sus logs.
Para lo que nos interesa, los tres mtodos de arriba son slo formas de transportar el token a travs de la
frontera de la API. El verdadero token subyacente mismo podra ser idntico.
20. Cacheo
HTTP provee un framework de cacheo incluido! Todo lo que tienes que hacer es incluir algunos
encabezados adicionales en la respuesta de salida y hacer una pequea validacin cuando recibes algn
encabezado de peticin de entrada.
Hay 2 alcances: ETag y Last-Modified
ETag: Cuando generas una peticin, incluye un encabezado HTTP ETag conteniendo un hash o checksum
de la representacin. Este valor debera cambiar cada vez que la salida cambia. Ahora, si una peticin de
entrada HTTP contiene un encabezado If-None-Match con un valor ETag, la API debera devolver un
cdigo de status 304 Not Modified en lugar de la salida del recurso.
Last-Modified (ltimo modificado): Bsicamente funciona como ETag, excepto en que usa timestamps.
El encabezado de respuesta Last-Modified contiene un timestamp en formato RFC 1123 el cual es
validado contra If-Modified-Since. Ntese que la especificacin de HTTP ha tenido 3 formatos de fecha
diferentes aceptables y el servidor debera estar preparado para aceptar cualquiera de ellos.
21. Errores
Sencillamente como una pgina HTML de error muestra un mensaje de error til a un visitante, una API
debera proveer un mensaje de error til en un formato conocido. La representacin de un error debera no
ser diferente a la representacin de cualquier recurso, con su propio set de campos.
La API debera devolver siempre cdigos de status HTTP prcticos. Los errores de la API generalmente
caen dentro de 2 tipos: la serie 400 de cdigos de status para problemas en el cliente y la serie 500 de
cdigos de status para problemas en el servidor. Como mnimo, la API debera estandarizar que todos los
errores de la serie 400 vengan en formato de error JSON. Si es posible (por ejemplo si los balanceadores
de carga y proxies reversos pueden crear cuerpos de error personalizables), este debera extender la serie
de cdigos de error 500.
El cuerpo de un error JSON debera proveer algunas cosas para el desarrollador un mensaje de error
til, un cdigo de error nico (que pueda ser buscado para ms detalles en la documentacin) y una
descripcin detallada. Una representacin de salida JSON de esta forma podra ser:
{
"code" : 1234,
"message" : "Algo malo ocurri :(",
"description" : "Mas detalles del error aqui"
}
Los errores de validacin para peticiones PUT, PATCH y POST necesitarn un breakdown en el campo.
Esto se modela mejor utilizando un cdigo de error de alto nivel arreglado para fallas de validacin que
proveen detalles del error en el campo adicional error, como por ejemplo:
{
"code" : 1024,
"message" : "Validacion fallida",
"errors" : [
{
"code" : 5432,
"field" : "nombre",
"message" : "El campo nombre no puede tener caracteres numericos"
},

{
"code" : 5622,
"field" : "password",
"message" : "Password cannot be blank"
}
]
}
22. Cdigos de estado HTTP
HTTP define un set de significativos cdigos de status que pueden ser devueltos por la API. stos pueden
ser nivelados para ayudar a los consumidores de la API dirigir sus respuestas apropiadamente. A
continuacin les dejo una lista de los que definitivamente deberas utilizar:

200 OK - Respuesta a un exitoso GET, PUT, PATCH o DELETE. Puede ser usado tambin para
un POST que no resulta en una creacin.

201 Created [Creada] Respuesta a un POST que resulta en una creacin. Debera ser
combinado con un encabezado Location, apuntando a la ubicacin del nuevo recurso.

204 No Content [Sin Contenido] Respuesta a una peticin exitosa que no devuelve un body
(como una peticin DELETE)

304 Not Modified [No Modificada] Usado cuando el cacheo de encabezados HTTP est activo

400 Bad Request [Peticin Errnea] La peticin est malformada, como por ejemplo, si el
contenido no fue bien parseado.

401 Unauthorized [Desautorizada] Cuando los detalles de autenticacin son invlidos o no son
otorgados. Tambin til para disparar un popup de autorizacin si la API es usada desde un
navegador.

403 Forbidden [Prohibida] Cuando la autenticacin es exitosa pero el usuario no tiene permiso
al recurso en cuestin.

404 Not Found [No encontrada] Cuando un recurso no existente es solicitado.

405 Method Not Allowed [Mtodo no permitido] Cuando un mtodo HTTP que est siendo
pedido no est permitido para el usuario autenticado.

410 Gone [Retirado] Indica que el recurso en ese endpoint ya no est disponible. til como
una respuesta en blanco para viejas versiones de la API

415 Unsupported Media Type [Tipo de contenido no soportado] Si el tipo de contenido que
solicita la peticin es incorrecto

422 Unprocessable Entity [Entidad improcesable] Utilizada para errores de validacin

429 Too Many Requests [Demasiadas peticiones] Cuando una peticin es rechazada debido a la
tasa lmite .

En conclusin
Una API es una interfaz de usuario para desarrolladores. Enfoca tu esfuerzo en asegurar que no sea slo
usable a nivel funcional sino tambin amigable.

You might also like