Publicado el 12/01/2014 por Antoine Chantalou , Jérémy Buisson , Florent Jaby Mohamed Kissa , Benoit Lafontaine.
Traducido del artículo Designer une API REST, el 29/05/2015 por Mary Rosales, Rolando Guevara paraGeoBolivia / ADSIB
La temporada navideña se acerca rápidamente , ofrecemos una » Tarjeta de referencia rápida » en el diseño de la API que pretende sintetizar el buen diseño y el diseño de la API REST.
➡ Descargar la API Diseño – Tarjeta de referencia rápida
Si usted tiene más tiempo , este artículo toma – punto por punto – los elementos de la » tarjeta de referencia » para apoyar y justificar las propuestas.
Disfruta leyendo!
- Introducción
- Conceptos generales
- KISS – » Keep it simple , stupid «
- Ejemplos CURL
- Granularidad media
- API Nombres de dominio
- Seguridad
- URI
- Nombres > Verbo
- Plural > singular
- Pausas consistentes
- Casse URI
- Casse del cuerpo
- Control de Versiones
- CRUD
- Respuestas parciales
- Cadenas de consulta
- Paginación
- Filtros
- Tris
- Búsqueda
- Encuentra Recursos
- Buscador Global
- Palabras reservadas : contar, último, primero, clase …
- Otros conceptos clave
- Negociación de Contenido
- Cross- dominio
- CORS
- jsonp
- HATEOAS
- Escenarios » No- Recursos «
- HTTP ERROR # Introducción
Cuando se desea concebir una API, se enfrenta rápidamente con el problema de «diseño API». Este punto constituye un problema importante, ya que una API mal diseñada probablemente será poco o no utilizada por nuestros clientes: los desarrolladores de aplicaciones.
La implementación de una API en el estado del arte requiere tener en cuenta:
- No sólo los principios sustantivos de los API RESTful procedentes de la literatura de referencia (Roy fielding, Leonard Richardson, Martin fowler, especificaciones HTTP…).
- Sino también las buenas prácticas utilizadas por los API de «Gigantes del Web».
En efecto, sucede que los dos enfoques se oponen: el de los «puristas», que militan para defender los principios RESTful sin concesiones, y el de «pragmáticos» que están a favor de un enfoque más práctico, para que su API sea funcional entre las manos de usuarios reales. A menudo, la respuesta justa se sitúa al medio ambiente.
Por otra parte, la fase de concepción/diseño de una API REST plantea una serie de problemas para las cuales las respuestas no son aún unánimes. Las buenas prácticas REST todavía están en vías de consolidación y hacen el enfoque apasionante.
A fin de facilitar y acelerar la aplicación de las API, proponemos nuestras convicciones procedentes de nuestras experiencias alrededor del tema API
Derecho: Este artículo es una recopilación de buenas prácticas, que pueden por supuesto ser discutidas. Le invitamos a participar en la reflexión y desafiar estas opciones sobre nuestro blog.
Conceptos Generales
KISS – « Keep it simple, stupid »
Uno de los objetivos de una estrategia API tiene por objeto «abrirse» de la WWW, para llegar a un público de desarrolladores más amplio posible. Por ello es primordial que la API sea lo más simple posible y auto-descriptiva, de manera que el usuario tenga que consultar la documentación lo menos posible. Se habla de affordance: es decir de la capacidad de la API a sugerir su utilización.
En el diseño de API, conviene tener en cuenta los siguientes principios:
- La semantiaca de una API debe ser intuitiva, en la URI de la carga de la peticion (payload) o de los datos de respuesta un usuario deberia ser capaz de usar la API usando la menor cantidad de documentacion de la API.
- Los términos utilizados deben ser usuales y concretos: clientes, pedidos, direcciones, productos, … y no extraídos de una «jerga funcional».
- Es conveniente no proponer a los usuarios de poder hacer algo de varias maneras diferentes.
➡ ¿Qué «Batidora» le parece ser lo más simple de usar?
La API es «designada» para los clientes: los desarrolladores, y no para los «datos» (representación interna de los datos de la empresa). La API expuesta deberá exponer las funcionalidades simples que responden a las necesidades del cliente. Un error frecuentemente encontrada es designar su API a partir de un modelo de datos existente, que es a menudo compleja.
➡ ¿Qué «Batidora» le parece ser lo más simple de usar?
Por último, en fase de diseño, conviene concentrarse en primer lugar sobre los «casos-utilizados» principales, y tratar los casos excepcionales en un segundo momento.
Ejemplos CURL
Entre los gigantes del Web, los ejemplos CURL son ampliamente utilizados para ilustrar las llamadas hacia su API:
- https://developer.github.com/v3/
- https://developers.google.com/youtube/v3/live/authentication#client-side-apps
- https://developer.paypal.com/docs/api/
- https://developers.facebook.com/docs/graph-api/making-multiple-requests
- https://www.dropbox.com/developers/blog/45/using-oauth-20-with-the-core-api
- http://instagram.com/developer/endpoints/likes/
- http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AESDG-chapter-instancedata.html
- …
Estamos a favor de ilustrar sistemáticamente sus llamadas de API mediante ejemplos CURL en la documentación de la API, que pueden ser utilizados en copiar y pegar, para eliminar toda ambigüedad sobre las modalidades de apelación.
➡ Ejemplo
CURL –X POST \
-H "Accept: application/json" \
-d '{"state":"running"}' \
https://api.fakecompany.com/v1/clients/007/orders
Granularidad Media
Si la teoría «un recurso = una URL» impulsa a cortar el conjunto de los recursos, nos parece importante mantener un límite razonable en este desglose.
Ejemplo: la información de una persona contiene una dirección actual que a su vez contiene un país.
Esto es para evitar tener que hacer 3 llamadas:
CURL https://api.fakecompany.com/v1/users/1234
< 200 OK
< {"id":"1234", "name":"Antoine Jaby", "address":"https://api.fakecompany.com/v1/addresses/4567"}
CURL https://api.fakecompany.com/addresses/4567
< 200 OK
< {"id":"4567", "street":"sunset bd", "country": "http://api.fakecompany.com/v1/countries/98"}
CURL https://api.fakecompany.com/v1/countries/98
< 200 OK
< {"id":"98", "name":"France"}
Mientras que estas informaciones se suelen utilizarse conjuntamente. Esto puede crear problemas de rendimiento vinculado a un número excesivo de llamadas.
Por el contrario , si se agrega demasiados datos a priori, se sobrecarga innecesariamente las llamadas, con el riesgo de generar intercambios demasiado prolijos.
De manera general exponer una API con granuralidad optima es frecuentemente cultural y el fruto de la experiencia en los temas de diseño de la API. En caso de duda evite enfocarse en cosas demasiado grandes o demasiado lentas
Más concretamente, pedimos:
- De no agrupar a los recursos que se accederá a raíz de manera casi sistemática.
- De no agrupar las colecciones podría tener muchos componentes. Por ejemplo, la lista de los puestos de trabajo corrientes son limitados (una persona no podrá acumularse mucho más que 2 o 3 empleos a tiempo parcial), por el contrario, la lista de experiencias profesionales puede ser muy larga.
- De limitarse a dos niveles de Anidamiento:
- /v1/users/addresses/countries
Nombres de dominios de las API
Entre los gigantes del Web, se observa que los dominios son dispares. Algunos utilizan varios dominios o subdominios para sus API: es sobre todo el caso de Dropbox.
➡ Entre los gigantes del Web
Para normalizar los nombres de dominio, en aras de realizar una acción, se recomienda utilizar sólo tres subdominios para la producción:
- API – https://api.{fakecompany}.com
- OAuth2 – https://oauth2.{fakecompany}.com
- Portal developer – https://developers.{fakecompany}.com
El objetivo es que el desarrollador, que utiliza la API, pueda determinar de manera intuitiva qué ámbito llamar, en función a lo que desea:
- Señalar a la API
- Recuperar una muestra para señalar a la API (vía OAuth2)
- Consultar el "portal de desarrollo" de la API
Por otra parte, PayPal propone un entorno "sandbox" para su API, muy práctica para poder realizar pruebas de "Try- It": https://developer.paypal.com/docs/api/
Proponemos el uso de dos sub-dominios específicos para una plataforma de pruebas :
Seguridad
Seguridad ambos protocolos son generalmente utilizados para proteger las API REST:
- OAuth1 : http://tools.ietf.org/html/rfc5849
- OAuth2 : http://tools.ietf.org/html/rfc6749
➡ Entre los gigantes del Web y en los DSI
OAuth1 | OAuth2 |
---|---|
Twitter, Yahoo, flickr, tumblr, Netflix, myspace, evernote,... | Google, Facebook, Dropbox, GitHub, amazone, Intagram, LinkedIn, foursquare, salesforce, viadeo, Deezer, Paypal, Stripe, huddle, boc, Basecamp, bitly,... |
MasterCard, CA-Store, OpenBankProject, intuit,... | AXA Banque, Bouygues telecom,... |
Recomendamos asegurar su API a través del protocolo OAuth2 .
A diferencia de OAuth1, OAuth2 permite gestionar la autenticación y la habilitación de los recursos por cualquier tipo de aplicación (nativo móvil, nativo tableta, aplicación javascript, aplicación web de tipo servidor, aplicación batch/back-Office, etc.), con o sin consentimiento de usuario propietario de los recursos.
OAuth2 es el estándar de seguridad de los API: proponer un protocolo marginal frenaría probablemente la aprobación de su API.
Por otra parte, los problemas de seguridad de los recursos son complejas, y una solución propietario implicaría a costar más riesgos significativos.
Proponemos de implementar la recomendación de Google para el flujo OAuth2 implícito relativo a la validación del token:
https://developers.google.com/accounts/docs/OAuth2UserAgent#validatetokenhttp://en.wikipedia.org/wiki/Confused_deputy_problem
Le recomendamos utilizar sistemáticamente el protocolo HTTPS para todos los accesos hacia:
- los proveedores de OAuth2
- los proveedores de API
Una excelente prueba para validar la buena implementación o aplicación de su solución OAuth2 consiste en lograr una llamada con el mismo código de cliente en su API, y sobre la API Google por ejemplo, teniendo que cambiar únicamente los nombres de dominio de servidores OAuth2 y API.
URIs
Nombres > Verbos
Para describir sus recursos, se recomienda utilizar los sustantivos concretos, no los verbos.
En informática, usamos desde hace mucho tiempo los verbos para exponer los servicios con un enfoque RPC, por ejemplo:
- getCliente (1)
- crearCliente()
- borrarDireccion(1)
- ...
Pero en un enfoque RESTfull , recomendamos utilizar :
- GET /clients/1
- POST /clients
- PATCH /accounts/1
- PUT /orders/1
- DELETE /addresses/1
- ...
Uno de los objetivos fundamentales de una API REST es precisamente de utilizar HTTP como protocolo de aplicación, para estandarizar y facilitar las interacciones entre si y para no tener que configurar un protocolo de "casa" de tipo SOAP/RPC o EJB, que tiene la desventaja de "reinventar la rueda" cada vez.
Por tanto, es necesario utilizar siempre verbos HTTP para describir las acciones realizadas en los recursos (véase CRUD ) .
Además, el uso de verbos HTTP hace que la API sea intuitiva y evita que el desarrollador tenga que consultar una documentación detallada para entender cómo manipular los recursos, favoreciendo así el uso y aplicación de la API.
En la práctica , el desarrollador cliente está generalmente equipado con herramientas (bibliotecas y frameworks) que permite generar peticiones HTTP con los verbos adecuados, a pertir de un modelo de objetos, cuando este último es actualizado.
Plural > singular
La mayoria de las veces los gigantes de la web permanecen consistentes entre los nombres de los recursos ya sea en singular o en plural. El principal problema actualmente es cuando se mezclan, De hecho los recuross donde los nombres varian entre plurales y singularres dificultan la "explorabilidad" de la API
Además, los nombres de los recursos nos parecen ser más natural en plural para dirigir de manera coherente las colecciones e instancias de recursos.
Se recomienda utilizar el plural para gestionar los dos tipos de recursos:
- Colección de Recursos: /v1/usuarios
- Una instancia de un recurso: /v1/usuarios/007
Para la creación de un usuario por ejemplo, se considera que POST /v1/usuarios es la invocación de la acción de creación en la colección de usuarios. Asimismo, para recuperar un usuario, GET /v1/usuarios/007, se leerá como "quisiera el usuario 007 en esta colección de usuarios".
Mayúsculas y minúsculas consistente
Mayúsculas y minúsculas de URI
Cuando se trata de nombrar a los recursos en un programa informático, se observa mayoritariamente 3 tipos de estilo: CamelCase, snake_case y spinal-case. Se trata de nombrar a los recursos de manera cercano del lenguaje natural evitando para ello no obstante de utilizar los espacios, las comillas o caracteres considerados demasiado exóticas. Esta práctica se ha establecido en los lenguajes de programación, cuando un conjunto reducido de caracteres queda autorizado para identificar las variables.
CamelCase: Este método se ha democratizado por el lenguaje Java. Es para diferenciar el principio de cada palabra al poner la primera letra en mayúscula. Ej. CamelCase, CurrentUser, AddAttributeToGroup, etc. Además de mesas redondas sobre la legibilidad, su principal defecto es ser inutilizable en contextos insensibles. Hay dos variantes :
- lowerCamelCase : donde la primera letra es minúscula.
- UpperCamelCase : cuando se escribe con mayúscula la primera letra .
snake_case: Este es el método utilizado desde hace mucho tiempo en C y más recientemente en Ruby. Las palabras se separan luego por subrayado "" para un compilador o intérprete de entender como un solo símbolo, pero para el lector humano para separar las palabras casi naturalmente. Su baja de popularidad se debe en parte al abuso de los programas en C o el uso de nombres largos o nombres ultra cortos. A diferencia del Camel Case, son muy pocos los contextos en los que es incompatible. Algunos ejemplos: snakecase, current_user, add_attribute_to_group, etc.
spinal-case: Variante de snake_case, utiliza guiones cortos "-" para separar las palabras. Las ventajas y desventajas son en gran parte idéntico a snake_case, excepto que muchos lenguajes de programación pueden aceptarlo como un símbolo (nombre de la variable o función). A veces se llama lisp-case como dialectos de LISP, es la forma habitual de nombrar variables y funciones. También es tradicionalmente la forma en que las carpetas y archivos se denominan en los sistemas UNIX y Linux. Ejemplos: spinal-case, current-user, add-attribute-to-group, etc.
Estos tres tipos de nomenclaturas cada uno con sus propias variantes en función de otros criterios como la mayúsculas y minúsculas utilizada para la primera Carta o el trato de los acentos y otros caracteres especiales. De manera general, se prefiere de cualquier manera utilizar el inglés básico, libre de caracteres especiales.
Según la RFC3986, los URL son "case sensitive" (salvo el esquema y el host). Pero en la práctica, una mayúsculas y minúsculas sensible puede causar disfunciones para las API alojadas en Windows.
Entre los Gigantes del Web:
Paypal | Amazon | dropbox | github | ||||
---|---|---|---|---|---|---|---|
snake_case | x | x | x | x | x | ||
spinal-case | x | x | |||||
camelCase | x |
Recomendamos utilizar para los URI una mayúsculas y minúsculas consistente, a elegir entre:
- spinal-case (destacado por la RFC3986)
- y snake_case (frecuentemente utilizada por los gigantes del Web) ➡ Ejemplos
POST /v1/specific-orders
o
POST /v1/specific_orders
Mayúsculas y minúsculas consistente de body
Para los datos contenidos en el body, se utilizan principalmente ambos formatos.
La calificación snake_case es considerablemente más utilizada por los gigantes del Web y, en particular, aprobada por las especificaciones OAuth2. En cambio, la popularidad del lenguaje Javascript contribuye significativamente a la aprobación de la calificación camelCase, aunque sobre el papel, REST debería defender la independencia del lenguaje y permitir exponer una API para el estado de la técnica xml.
Recomendamos utilizar para los URI una mayúsculas y minúsculas consistente, a elegir entre:
- snake_case (frecuentemente utilizada por la comunidad Web Ruby…)
- lowerCamlCase (frecuentemente utilizada por las comunidades Javascript, Java…)
➡ Ejemplos
GET /orders?id_client=007 or GET /orders?idClient=007
POST /orders {"id_client":"007"} or POST/orders {"idClient":"007”}
Control de versiones
Toda API estará obligada a evolucionar en el tiempo. Una API puede ser versionada de distintas maneras:
- Por indicación de la hora, por número de versión...
- En el path, al comienzo o al final de la URI
- En parámetro de la solicitud (request)
- En un header HTTP
- Con un control de versiones voluntario u obligatorio
➡ Entre los gigantes del Web
Se recomienda incluir un número de versión obligatorio, un dígito en el nivel más alto de la ruta URI.
- El número designará a una versión mayor de la API de un recurso, que exige un cambio para que la API funcione.
- REST y Json permiten, entre otras cosas, en comparación con SOAP/XML, una cierta flexibilidad para hacer evolucionar el API sin tener que afectar (redistribución) de los clientes. Por ejemplo, añadiendo atributos a un recurso existente. La versión de la API no tiene que ser incrementada en este caso.
- El control de versiones por defecto se evita ya que en caso de cambio de la API, los efectos sobre las aplicaciones que llaman no serían controlados por los clientes.
- La versión de una API es la información esencial , damos prioridad a los temas de affordance , para que aparezca en la dirección URL en lugar de la cabecera HTTP .
- Estamos a favor de tener dos versiones en paralelo ( el ciclo de adopción por las aplicaciones nativas es a menudo más largo).
➡ Ejemplo GET /v1/orders
CRUD
Como hemos señalado, uno de los objetivos fundamentales del enfoque REST es precisamente de utilizar HTTP como Protocolo de aplicación para no tener que configurar una API "casa".
Il convient donc d’utiliser systématiquement les verbes HTTP pour décrire les actions réalisées sur les ressources, et de faciliter le travail du développeur pour les manipulations CRUD récurrentes. Le tableau suivant synthétise les bonnes pratiques généralement constatées :
Por tanto, es necesario utilizar siempre verbos HTTP para describir las acciones realizadas en los recursos, y facilitar el trabajo de los desarrolladores para las manipulaciones CRUD recurrentes. El cuadro siguiente resume las buenas prácticas generalmente reconocidas:
Verbo HTTP | Correspondencia CRUD | Colección / pedidos | Instancia : / pedidos / { id} |
---|---|---|---|
GET | READ | Leer una lista de órdenes.. 200 OK. | Leer el detalle de un solo pedido. 200 OK. |
POST | CREATE | Crear una nueva orden. 201 Creado. | – |
PUT | UPDATE/CREATE | – | Actualización Completa. 200 OK. Crear una orden específica. 201 Creado. |
PATCH | UPDATE | – | Actualización parcial. 200 OK. |
DELETE | DELETE | – | Eliminar una orden. 200 OK. |
El verbo HTTP POST es utilizado para crear una instancia dentro de una colección. El ID del recurso a crear no debe ser señala:
CURL –X POST \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"state":"running","id_client":"007"}' \
https://api.fakecompany.com/v1/clients/007/orders
< 201 Created
< Location: https://api.fakecompany.com/orders/1234
El código de retorno no es 200 sino 201 . El URI y el nuevo identificador de recurso regresaron en la cabecera " Location" de la respuesta. Mayúsculas y minúsculas consistente Si el identificador del recurso especificado por el cliente, el verbo HTTP PUT se utiliza para crear una instancia de la colección. Sin embargo, en la práctica, este caso de utilización es menos frecuente.
CURL –X PUT \
-H "Content-Type: application/json" \
-d '{"state":"running","id_client":"007"}' \
https://api.fakecompany.com/v1/clients/007/orders/1234
< 201 Created
El verbo HTTP PUT se utiliza sistemáticamente para lograr una actualización total de una instancia de la colección (todos los atributos son reemplazados y los que no están presentes se borrarán).
Dans l’exemple ci-dessous, on met à jour l’attribut state et l’attribut id_client. Tous les autres champs seront supprimés.
En el siguiente ejemplo, actualizamos el atributo de state y el atributo customer_id. Todos los otros campos serán eliminados .
CURL –X PUT \
-H "Content-Type: application/json" \
-d '{"state":"paid","id_client":"007"}' \
https://api.fakecompany.com/v1/clients/007/orders/1234
< 200 OK
El verbo HTTP PARCHE (no presente inicialmente en las especificaciones HTTP pero se añadirá más adelante) es habitualmente utilizado para una actualización parcial de una instancia de la colección.
En el siguiente ejemplo , actualizamos el atributo de state, pero otros atributos se mantienen sin cambios.
CURL –X PATCH \
-H "Content-Type: application/json" \
-d '{"state":"paid"}' \
https://api.fakecompany.com/v1/clients/007/orders/1234
< 200 OK
Le verbe HTTP GET est utilisé pour lire une collection. En pratique, l’API ne retourne généralement pas l’intégralité des réponses (voir section Pagination).
El verbo HTTP GET se utiliza para leer una colección. En la práctica, la API no suele volver todas las respuestas (ver sección de paginación ) .
CURL –X GET \
-H "Accept: application/json" \
https://api.fakecompany.com/v1/clients/007/orders
< 200 OK
< [{"id":"1234", "state":"paid"}, {"id":"5678", "state":"running"}]
El verbo HTTP GET se utiliza para leer la instancia de una colección .
CURL –X GET \
-H "Accept: application/json" \
https://api.fakecompany.com/v1/clients/007/orders/1234
< 200 OK
< {"id":"1234", "state":"paid"}
Respuestas parciales
Las respuestas parciales permiten al cliente de recuperar únicamente la información que necesita. Esta característica es, por otra parte primordial para los contextos en uso nómada (3G-), o la amplitud de banda debe ser optimizada.
➡ Entre los gigantes del Web
API | Respuestas parciales |
---|---|
?fields=url,object(content,attachments/url) | |
&fields=likes,checkins,products | |
https://api.linkedin.com/v1/people/~:(id,first-name,last-name,industry) |
Como mínimo , se recomienda seleccionar los atributos a subir, en un nivel de recursos a través de los campos de notación Google field = atributo1 , atributoN :
GET /clients/007?fields=firstname,name
200 OK
{
"id":"007",
"firstname":"James",
"name":"Bond"
}
En los casos en que el rendimiento es un tema importante, nos proponemos utilizar la notacion de campos Google que es field=object(attribute1,atributeN), Por ejemplo, para recuperar solo el primer nombre, el nombre y la direccion de la calle de un cliente.
GET /clients/007?fields=firstname,name,address(street)
200 OK
{
"id":"007",
"firstname":"James",
"name":"Bond",
"address":{"street":"Horsen Ferry Road"}
}
Cadena de Consulta
Paginación
Es necesario proporcionar al comienzo de su API de la paginación de sus recursos. De hecho, es difícil anticipar con precisión la evolución de la cantidad de datos que será devuelto. Es por ello que recomendamos paginar sus recursos con los valores por defecto cuando no se especifican, por ejemplo, con un rango de valores [0-25].
Paginación sistemática también trae consistencia de sus recursos, que sólo puede ser beneficioso porque no hay que olvidar que la descripción de una API debe ser autosuficiente: contar con documentación para poder leerlo.
Algunos ejemplos de los gigantes de la Web
API Facebook
Parametros: before, after, limit, next, previews
"paging":{
"cursors":{
"after":"MTAxNTExOTQ1MjAwNzI5NDE=",
"before":"NDMyNzQyODI3OTQw"
},
"previous":"https://graph.facebook.com/me/albums?limit=25&before=NDMyNzQyODI3OTQw"
"next":"https://graph.facebook.com/me/albums?limit=25&after=MTAxNTExOTQ1MjAwNzI5NDE="
}
API Google
Parametros: maxResults, pageToken
"NextPageToken":"CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA",
API Twitter
Parametros: since_id, max_id, count
"next_results":"?max_id=249279667666817023&q=*freebandnames&count=4&include_entities=1&result_type=mixed",
"count":4,
"completed_in":0.035,
"since_id_str":"24012619984051000",
"query":"*freebandnames",
"max_id_str": "250126199840518145"
API GitHub
Parametros: page, per_page
Link:;rel="next",
;rel="last"
Paypal
Parametros: start_id, count
{ 'count':1, 'next_id':'PAY-5TU010975T094876HKKDU7MZ',
Diversos mecanismos de Paginación son utilizados por los gigantes del Web. Puesto que ningún principio común no se desprende verdaderamente, proponemos de utilizar: el parámetro de petición ?rango=0-25 y los header estándar HTTP para la respuesta: Content-Range Accept-Range
Varios mecanismos de paginación son utilizados por los gigantes de la Web. Dado que ningún de ellos es común, nosotros podemos utilizar:
- El parámetro de consulta /?rango=0-25
- Y el encabezado estándar HTTP para la respuesta:
- Content-Range
- Accept-Range
La paginación en la solicitud.
Desde un punto de vista práctico , a menudo logrado la paginación en el URL a través de la cadena de consulta. Las cabeceras HTTP también proporcionan este mecanismo. Proponemos a aceptar solamente la solución a través de cadena de consulta, e ignorar el Range encabezado HTTP. La paginación es una información importante que los intereses para realizar la accion se pueden colocar en la consulta.
Le recomendamos que utilice un rango de valores, utilizando el índice de sus recursos. Por ejemplo, el rango de recursos 10 a 25 puede ser iguales a ?rango=10-25.
La paginación en la respuesta
La Paginación en la respuesta el código de retorno HTTP correspondiente al regreso de una solicitud hoy es 206 por un contenido parcial. Salvo, si los valores solicitadas provocan la recuperación del conjunto de los datos de la colecciones, en cuyo caso el código de retorno es 200 OK. La respuesta de su API sobre una colección deberá obligatoriamente revelar las cabeceras de HTTP.
- Content-Range offset – limit / count
- offset : Indice del primer elemento devuelto por la solicitud.
- limit : Indice del ultimo elemento devuelto por la solicitud.
- count : El numero total de elementos que contiene la coleccion.
- Accept-Range resource max
- resource : Tipo de la paginación, se hablará aquí sistemáticamente del recurso de usro, ex: cliente, Order, restaurante, .....
- max : Numero maximo de peticiones en una sola vez.
En el caso de que la paginación solicitada no encuentra en los valores toleradas por el API, la respuesta HTTP será un código error 400.
Vínculos de navegación
Es altamente recomendable incorporar en las cabeceras HTTP de sus respuestas la etiqueta Link. Esto le permite añadir, entre otras cosas, los vínculos de navegación como la siguiente página, la página anterior, primera página, última página, etc ...
Ejemplos Tenemos en nuestra API de una colección de 48 restaurantes, donde se puede ver que el limite es 50 por la solicitud. La paginación por defecto es 0-50:
CURL –X GET \
-H "Accept:application/json" \
https://api.fakecompany.com/v1/restaurants
< 200 Ok
< Content-Range: 0-47/48
< Accept-Range: restaurant 50
< [...]
Si se solicitan 25 recursos, de los 48 disponibles, se devuelve un código de contenido parcial 206:
CURL –X GET \
-H "Accept:application/json" \
https://api.fakecompany.com/v1/restaurants?range=0-24
< 206 Partial Content
< Content-Range: 0-24/48
< Accept-Range: restaurant 50
Si se solicitan 50 los recursos, de los 48 disponibles, el código se devuelve 200 OK:
CURL –X GET \
-H "Accept:application/json" \
https://api.fakecompany.com/v1/restaurants?range=0-50
< 200 Ok
< Content-Range: 0-47/48
< Accept-Range: restaurant 50
Si el rango solicitado excede el número máximo de recursos en una consulta, una vez(header Accept-Range), el código devuelto sera 400 KO:
CURL –X GET \
-H "Accept:application/json" \
https://api.fakecompany.com/v1/orders?range=0-50
< 400 Bad Request
< Accept-Range: order 10
< { reason : "Requested range not allowed" }
Para volver enlaces a otras playas, le recomendamos la siguiente notación, utilizado por GitHub, compatible con RFC5988 (y que podemos manejar clientes que no permiten encabezado múltiple "Link")
CURL –X GET \
-H "Accept:application/json" \
https://api.fakecompany.com/v1/orders?range=48-55
< 206 Partial Content
< Content-Range: 48-55/971
< Accept-Range: order 10
< Link : ; rel="first", ; rel="prev", ; rel="next", ; rel="last"
Otra notación se encuentra comúnmente en la cabecera HTTP es el Enlace etiqueta que consiste en una URL, seguido por el tipo de enlaces relacionados. Esta etiqueta se puede repetir tantas veces como se relacionan con su respuesta:
< Link: ; rel="first"
< Link: ; rel="prev"
< Link: ; rel="next"
< Link: ; rel="last"
La siguiente notación utilizada por Paypal:
[
{"href":"https://api.fakecompany.com/v1/orders?range=0-7", "rel":"first", "method":"GET"},
{"href":"https://api.fakecompany.com/v1/orders?range=40-47", "rel":"prev", "method":"GET"},
{"href":"https://api.fakecompany.com/v1/orders?range=56-64", "rel":"next", "method":"GET"},
{"href":"https://api.fakecompany.com/v1/orders?range=968-975", "rel":"last", "method":"GET"},
]
Filtros
Un filtro sirve para limitar el número de recursos solicitados, especificando los atributos y sus correspondientes valores esperados. Es posible filtrar una colección de varios atributos simultáneamente, y permitir que más valores para el mismo atributo se filtren.
Para ello, nos proponemos utilizar el nombre del atributo con un equivalente de los valores esperados, cada uno separado por una coma.
Ejemplo: Consulta de restaurantes que preparan comida thai.
CURL –X GET \
-H "Accept: application/json" \
https://api.fakecompany.com/v1/restaurants?type=thai
This is [on GitHub](https://github.com/jbt/markdown-editor) so let me know if I've b0rked it somewhere.
Ejemplo: Consulta de restaurantes con una calificación de 4 o 5, con cocina japanese o chinese, abierto los domingos(sanday).
CURL –X GET \
-H "Accept: application/json" \
https://api.fakecompany.com/v1/restaurants?type=japanese,chinese&rating=4,5&days=sunday
Ordenar
Ordenar el resultado de una solicitud a una colección de recursos pasa por dos parámetros principales:
sort: Contiene los nombres de los atributos, separados por comas, por los que se efectura la ordenacion.desc: La ordenacion por defecto es ascendente (o descendente) para ordenar de abajo (o descendente), sólo tiene que añadir este parámetro (sin defecto). Si queremos, en algunos casos especificar qué atributos deben ser tratados en orden ascendente o descendente, entonces lo haremos en este parámetro la lista de atributos descendientes, y los demas por los ascendientes por defecto.
Ejemplo: Consultar de los restaurantes ordenados alfabéticamente en el nombre.
CURL –X GET \
-H "Accept: application/json" \
https://api.fakecompany.com/v1/restaurants?sort=name
Ejemplo: Consulta de los restaurantes, ordenado por valoración descendente, y luego descendiendo número de comentarios y, finalmente, en orden alfabético en el nombre.
CURL –X GET \
-H "Accept: application/json" \
https://api.fakecompany.com/v1/restaurants?sort=rating,reviews,name&desc=rating,reviews
Ordenar, filtra y paginación La página necesariamente será afectado por cambios de clasifica y de filtro. La combinación de los tres suplementos de consulta debe estar anidado en cualquier coherencia en sus solicitudes de la API.
Ejemplo: Solicitar a los 5 primeros restaurantes chinese(chinos) ordenados por categoría descendente.
CURL –X GET \
-H "Accept: application/json" \
https://api.fakecompany.com/v1/restaurants?type=chinese&sort=rating,name&desc=rating&range=0-4
< 206 Partial Content
< Content-Range: 0-4/12
< Accept-Range: restaurants 50
Busquedas
Encuentra Recursos Cuando realizamos un filtrado no es suficiente (parcial o acercarse), ahora vamos a ir a través de una búsqueda en los recursos.
Las busquedas es en sí mismo una sub-recursos de su colección, ya que los resultados que proporciona tendrán un formato diferente de los recursos deseados. Esto permite añadir las sugerencias, correcciones y noticias de la busqueda.
Los parámetros son prestados de la misma manera que para el filtro, mediante la consulta, pero éstos no sean forzosamente para dar valores exactos, y podrán tener una nomenclatura para hacer la busqueda mas cercana.
Las busquedas es un recurso de propiedad total, que debe ser compatible con la paginación de la misma manera que otros recursos de la API Web.
Ejemplo: Búsqueda de restaurantes cuyo nombre empieza por « La ».
CURL –X GET \
-H "Accept: application/json" \
https://api.fakecompany.com/v1/restaurants/search?name=la*
< 206 Partial Content
< { "count" : 5, "query" : "name=la*", "suggestions" : ["las"], results : [...] }
Ejemplo: buscar en los 10 mejores restaurantes tienen « napoli » en su nombre, con la cocina chinese o japanese, que se encuentra en el 75 (París), ordenados en función de su calificación por su nombre y por orden alfabético.
CURL –X GET \
-H "Accept: application/json" \
-H "Range 0-9" \
https://api.fakecompany.com/v1/restaurants/search?name=*napoli*&type=chinese,japanese&zipcode=75*&sort=rating,name&desc=rating&range=0-9
< 206 Partial Content
< Content-Range: 0-9/18
< Accept-Range: search 20
< { "count" : 18, "range": "0-9", "query" : "name=*napoli*&type=chinese,japanese&zipcode=75*", "suggestions" : ["napolitano", "napolitain"], results : [...] }
Buscador Global
La búsqueda global se comportará de la misma manera que una búsqueda por recurso, simplemente se encuentra en la raíz de su PLC y se debe especificar claramente en su documentación.
Estamos a favor de la notación utilizada por Google para búsquedas globales:
CURL –X GET \
-H "Accept: application/json" \
https://api.fakecompany.com/v1/search?q=running+paid
< [...]
Otros conceptos clave
Negociación de contenido
Se recomienda administrar formato de distribución múltiple el contenido de su API. Lo utilizaremos para la cabecera HTTP para este propósito: «Accept»
Por defecto, el API distribuirá los recursos en formato JSON, pero en los casos en que la solicitud primero especifique "Accept: application/xml", los recursos será proporcionado en formato XML.
Es aconsejable administrar un mínimo de 2 formatos: JSON y XML. El orden de los formatos requeridos por la cabecera «Accept» se debe respetar para definir el formato de la respuesta. Cuando no sea posible proporcionar el formato solicitado, un error http 406 se devuelve (ver Errores - Códigos de estado).
GET https://api.fakecompany.com/v1/offers
Accept: application/xml; application/json XML de preferencia JSON
< 200 OK
< [XML]
GET https://api.fakecompany.com/v1/offers
Accept: text/plain; application/json Text non pris en charge par l’api
< 200 OK
< [JSON]
Cross-domain CORS Cuando la aplicación (javascript SPA) y la API se encuentran en diferentes dominios, por ejemplo:
Una buena práctica es utilizar el protocolo CORS que es el estándar HTTP.
La aplicación de servidor CORS suele añadir algunas pautas para el servidor HTTP(Nginx/Apache/nodejs...).
Del lado del cliente, la aplicación es transparente: el navegador realizará antes de cada petición GET/POST/PUT/PATCH/DELETE peticiones HTTP con el verbo OPTIONS.
Aquí, por ejemplo, dos llamadas sucesivas que realizan un navegador para recuperar, a través de GET, la información de un usuario en la API de Google+:
CURL -X OPTIONS \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
'https://www.googleapis.com/plus/v1/people/105883339188350220174?client_id=API_KEY'
CURL -X GET\
'https://www.googleapis.com/plus/v1/people/105883339188350220174?client_id=API_KEY' \
-H 'Accept: application/json, text/javascript, */*; q=0.01'\
-H 'Authorization: Bearer foo_access_token'
Jsonp En la práctica, CORS no es (o mal) con el apoyo de los navegadores más antiguos, incluyendo IE7,8 y 9. Si su API es utilizado por los navegadores que no ha dominado (Internet, con los usuarios finales), que siendo necesario para proponer una exposición JSONP API en CORS en la implementación de retorno.
En la práctica, es un JSONP te permiten ermitir la elusión del uso de la etiqueta script /≶ para permitir la gestión de varios dominios. Usando JSONP, tiene ciertas limitaciones:
- No se puede usar la negociación de contenido a través de la cabecera Accept = > Un nuevo punto final debe ser publicado con el .jsonp extensión por ejemplo, para permitir que el controlador para determinar que se trata de una solicitud jsonp.
- Todas las solicitudes se envían a través de los protocolos HTTP GET verbo=> método parámetro =XXX debe ser propuesto.
- Tenga en cuenta que un rastreador web puede dañar gravemente sus datos si no hay verificación de autorización se realiza en la llamada al método = DELETE por ejemplo...
- La carga útil de la solicitud no puede ser explotado para transportar datos=> todos los datos deben ser enviados en el parámetro de la petición.
Para CORS y jsonp compatible, su PC debe exponer ejemplo los siguientes criterios de valoración:
POST /orders et /orders.jsonp?method=POST&callback=foo
GET /orders et /orders.jsonp?callback=foo
GET /orders/1234 et /orders/1234.jsonp?callback=foo
PUT /orders/1234 et /orders/1234.jsonp?method=PUT&callback=foo
HATEOAS
Concepto
Tomemos el ejemplo de Angelina Jolie, cliente de Amazon que desee examinar los detalles de su última orden. Para ello, tendrá que realizar dos acciones:
- Lista de todos los ordenes
- Seleccionar el último orden
En el sitio web de Amazon, Angelina no tiene que ser un experto en web para leer su última orden: sólo tiene que conectar al sitio con su cuenta, haga clic en el enlace "mis órdenes" y seleccione el último.
Imagina que Angelina quiere utilizar una API para realizar la misma acción!
Se debe consultar primero a Amazon la documentación para encontrar la URL que le permitirá a la lista de sus controles. Una vez encontrado, se debe jugar la url que devolverá una lista de los comandos. Ella va a ver a su orden, pero para acceder a ella necesitará otra URL. Agelina tendrá que consultar la documentación para la construcción de la URL correspondiente.
La diferencia entre estos dos escenarios es que en el primero, Angelina tenía que saber que la primera URL: "http://www.amazon.com" y se guiará por los enlaces en la página web. Pero en el segundo caso, Angelina se vio obligado a consultar la documentación para la construcción de la URL.
La desventaja del segundo enfoque es que:
- En condiciones reales, la documentación no siempre es actual.
- Angelina puede ir junto a uno o más servicios disponibles, ya que no están debidamente documentados.
- Angelina suele ser un desarrollador, y los desarrolladores no son particularmente aficionados documentación.
- El API pierde la accesibilidad.
Asumiendo nuestra Angelina desarrolló un proceso por lotes para automatizar esta acción. ¿Qué va a pasar cuando Amazon cambiará su URL?
Implementación
En la práctica, HATEOAS es un poco como la meteorología: "Todo el mundo habla sobre el clima, pero nadie hace nada al respecto."
Entre Gigantes Web , PayPal proporciona una implementación:
[
{
"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-6RV70583SB702805EKEYSZ6Y",
"rel": "self",
"method": "GET"
},
{
"href": "https://www.sandbox.paypal.com/webscr?cmd=_express-checkout&token=EC-60U79048BN7719609",
"rel": "approval_url",
"method": "REDIRECT"
},
{
"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-6RV70583SB702805EKEYSZ6Y/execute",
"rel": "execute",
"method": "POST"
}
]
Utilizando esta notación, una llamada a /clientes/007 información de la declaración del cliente, sino también punteros a los diferentes estados:
GET /clients/007
< 200 Ok
< { "id":"007", "firstname":"James",...,
"links": [
{"rel":"self","href":"https://api.domain.com/v1/clients/007", "method":"GET"},
{"rel":"addresses","href":"https://api.domain.com/v1/addresses/42", "method":"GET"},
{"rel":"orders", "href":"https://api.domain.com/v1/orders/1234", "method":"GET"},
...
]
}
Para la aplicación de HATEOAS, nos proponemos utilizar la notación abajo, utilizado por GitHub, compatible con RFC5988 (que le permite administrar el cliente que no admite encabezado múltiple "Link"):
GET /clients/007
< 200 Ok
< { "id":"007", "firstname":"James",...}
< Link : ; rel="self"; method:"GET",
< ; rel="addresses"; method:"GET",
< ; rel="orders"; method:"GET"
Escenarios "No-Recursos"
Según el RESTfull teoría, todas las aplicaciones deben ser vistos y tratados como un recurso. Pero en la práctica esto no siempre es posible, sobre todo cuando se habla de la operación como la traducción, el cálculo, conversión o servicios a las empresas a veces complejas.
En estos casos, su operación debe estar representado por un verbo y no un sustantivo. Por ejemplo:
POST /calculator/sum
[1,2,3,5,8,13,21]
< 200 OK
< {"result" : "53"}
O:
POST /convert?from=EURato=USD&amount=42
< 200 OK
< {"result" : "54"}
Así que uno llega a tener que utilizar las acciones y no de recursos. Para ello, vamos a utilizar el verbo POST HTTP.
CURL –X POST \
-H "Content-Type: application/json" \
https://api.fakecompany.com/v1/users/42/carts/7/commit
< 200 OK
< { "id_cart": "7", [...] }
Para entender correctamente esta excepción para modelar su API, el más simple y asumir que cualquier solicitud POST es una acción, que tiene un verbo por defecto cuando no se especifica.
En el caso de una colección de recursos, por ejemplo, la acción predeterminada es crear:
POST /users/create POST /users
< 201 OK == < 201 OK
< { "id_user": 42 } < { "id_user": 42 }
En el caso de un recurso de "e-mail ", la acción predeterminada se envía al destinatario:
POST /emails/42/send POST /emails/42
< 200 OK == < 200 OK
< { "id_email": 42, "state": "sent" } < { "id_email": 42, "state": "sent" }
Sin embargo, es esencial tener en cuenta que el uso del verbo en sus consultas REST debe seguir siendo una excepción. Y que en la gran mayoría de los casos debe evitarse esta excepción. El hecho de que un recurso tiene múltiples acciones, o que los grandes recursos de exponer al menos una acción, es una alerta para el diseño de su API.
Esto generalmente significa que ha adoptado un enfoque de RPC en lugar de REST, será necesario tomar medidas rápidas para reanudar el diseño de su API en la mano.
Con el fin de evitar la creación de cualquier tipo de confusión para los desarrolladores entre los recursos (en el que uno puede hacer CRUD) y operaciones, es altamente recomendable distinguir entre estas dos partes de la documentación del desarrollador.
Los gigantes de la Web
API | No-Recursos |
---|---|
Google Translate API | GET https://www.googleapis.com/language/translate/v2?key=INSERT-YOUR-KEY&target=de&q=Hello%20world |
Google Calendar API | POST https://www.googleapis.com/calendar/v3/calendars/calendarId/clear |
Twitter Authentification | GET https://api.twitter.com/oauth/authenticate?oauth_token=Z6eEdO8MOmk394WozF5oKyuAv855l4Mlqo7hhlSLik |
Errores
Se recomienda utilizar la siguiente estructura JSON:
{
"error": "description_courte",
"error_description": "Descripcion larga, Legible para el humano",
"error_uri": "URI a una descripción detallada del error en el portal a desarrollar"
}
El indicador de error no es necesariamente tiene que ser redundante con el estado HTTP: es posible tener dos estados diferentes para el mismo valor en el "error" clave y viceversa.
- 400 & error=invalid_user
- 400 & error=invalid_cart
Esta representación se basa en la OAuth2 especificación. Su generalización a la API permitirá a los clientes que consume tener que manejar dos errores con estructuras distintas.
Nota: puede ser apropiado en algunos casos para proporcionar una colección de esta estructura para devolver varios errores simultáneos (útiles en el caso de un ejemplo de validación de formularios del lado del servidor).
Codigos de Estado
Le recomendamos encarecidamente el uso de los códigos de retorno HTTP, apropiadamente, sabiendo que hay un código para cada caso de uso actual. Estos códigos son conocidos por todos. No absolutamente es necesario utilizar todos los códigos, pero la docena de códigos más utilizados a menudo es suficiente.
Success (exito)
200 OK: código clásico de éxito, que opera en los casos más importantes. Especialmente uitilisé durante una exitosa primera petición GET en un recurso.
HTTP Status | Descripcion |
---|---|
201 Created (creado) | Indica que un recurso ha sido creado. Esta es la respuesta típica a PUT y solicitud POST, incluyendo una cabecera HTTP "ubicación" de la dirección URL del recurso. |
202 Accepted (aceptado) | Indica que la solicitud ha sido aceptada para su posterior procesamiento. Esta es la respuesta típica a una llamada asincrónica (para una UX o un mejor rendimiento,...). |
204 No content (Sin contenido) | Indica que la solicitud se haya procesado con éxito , pero no hay respuesta a volver. A menudo devuelto en respuesta a una ELIMINAR. |
206 Content Content (Contenido parcial) | La respuesta es incompleta. Normalmente devuelto por respuestas paginados. |
Cliente error (error de cliente)
HTTP Status | Descripcion |
---|---|
400 Bad Request (peticion incorrecta) | Normalmente se utiliza para localizar errores de llamadas, si no hay otro estado coincide. Hay dos tipos de errores. El comportamiento de error de solicitud, por ejemplo: |
GET /users?payed=1
< 400 Bad Request
< {"error": "invalid_request", "error_description": "There is no ‘payed' property on users."}
HTTP Status | Descripcion |
---|---|
400 Bad Request (peticion incorrecta) | Condiciones de error de aplicación, ejemplo: |
POST /users
{"name":"John Doe"}
< 400 Bad Request
< {"error": "invalid_user", "error_description": "A user must have an email adress"}
HTTP Status | Descripcion |
---|---|
401 Unauthorized (peticion incorrecta) | No sé tú, dime quién eres y voy a ver tus autorizaciones. |
GET /users/42/orders
< 401 Unauthorized
< {"error": "no_credentials", "error_description": "This resource is under permission, you must be authenticated with the right rights to have access to it" }
HTTP Status | Descripcion |
---|---|
403 Forbidden | Usted está autenticado con éxito, pero no está suficientemente cualificado. |
GET /users/42/orders
< 403 Forbidden
< {"error": "not_allowed", "error_description": "You're not allowed to perform this request"}
HTTP Status | Descripcion |
---|---|
404 Not Found (no encontrado) | El recurso que ha solicitado no existe. |
GET /users/999999/
< 400 Not Found
< {"error": "not_found", "error_description": "The user with the id ‘999999' no existe" }
HTTP Status | Descripcion |
---|---|
405 Method not allowed (metodo no permitido | O llamar a un método no tiene sentido en este recurso, ya sea por que el usuario no está autorizado para realizar esta llamada. |
POST /users/8000
< 405 Method Not Allowed
< {"error":"method_does_not_make_sense", "error_description":"How would you even post a person?"}
HTTP Status | Descripcion |
---|---|
406 Not Acceptable | Nada coincide con la consulta * Accept- Header . Por ejemplo , usted solicita un recursos XML o los recursos es sólo avaialble en JSON. |
GET /usersAccept: text/xmlAccept-Language: fr-fr
< 406 Not Acceptable
< Content-Type: application/json
< {"error": "not_acceptable", "available_languages":["us-en", "de", "kr-ko"]}
Error del servidor
HTTP Status | Descripcion |
---|---|
500 Server error | La referencia del recurso es válido, pero se encontró con un problema de rendimiento. El cliente no puede realmente hacer nada al respecto. Proponemos volver sistemáticamente el estado 500. |
GET /users
< 500 Internal server error
< Content-Type: application/json
< {"error":”server_error", "error_description":"Oops! Something went wrong..."}
Fuentes
- Design Beautiful REST + JSON APIs
- Web API Design: Crafting Interfaces that Developers Love
- HTTP API Design Guide
- RESTful Web APIs
- REST World
Traducido por:
Menciones legales
Traducción autorizada por OCTO Technology según las siguientes menciones legales.
©2014 OCTO Technology. Todos derechos reservados
Las informaciones contenidas en este documento representan el punto de vista actual de OCTO Technology sobre los temas expuestos, a la fecha de publicación. Cualquier extracto o difusión parcial es prohibido sin la autorización previa de OCTO Technology. Los nombres de productos o de empresas citados en este documento pueden ser marcas registradas de sus propietarios respectivos.
[…] URL: https://blog.agetic.gob.bo/?p=142 […]
[…] cubre los diferentes tipos de servicio distribuido como CORBA, SOAP o REST, pero también las bases de datos no locales y los sistemas de archivos […]