Mejores prácticas de REST API: ¿dónde poner los parámetros?

Una API REST puede tener parámetros de al menos dos formas:

  1. Como parte de la ruta URL (es decir, /api/resource/parametervalue )
  2. Como un argumento de consulta (es decir, /api/resource?parameter=value )

¿Cuál es la mejor práctica aquí? ¿Hay alguna guía general sobre cuándo usar 1 y cuándo usar 2?

Ejemplo del mundo real: Twitter usa parámetros de consulta para especificar intervalos. ( http://api.twitter.com/1/statuses/home_timeline.json?since_id=12345&max_id=54321 )

¿Se consideraría mejor diseño colocar estos parámetros en la ruta URL?

Si hay buenas prácticas documentadas, aún no las he encontrado. Sin embargo, aquí hay algunas pautas que utilizo para determinar dónde poner parámetros en una url:

Los parámetros opcionales tienden a ser más fáciles de poner en la cadena de consulta.

Si desea devolver un error 404 cuando el valor del parámetro no corresponde a un recurso existente, me inclinaría por un parámetro de segmento de ruta. eg /customer/232 donde 232 no es una identificación de cliente válida.

Sin embargo, si desea devolver una lista vacía, cuando no se encuentre el parámetro, le sugiero usar los parámetros de cadena de consulta. eg /contacts?name=dave

Si un parámetro afecta a un subárbol completo de su espacio de URI, utilice un segmento de ruta. por ejemplo, un parámetro de idioma /en/document/foo.txt versus /en/document/foo.txt

Prefiero que los identificadores únicos estén en un segmento de ruta en lugar de un parámetro de consulta.

Las reglas oficiales para los URI se encuentran en esta especificación de RFC aquí . También hay otra especificación RFC muy útil aquí que define reglas para parametrizar URI.

Respuesta tardía, pero añadiré algo de información adicional a lo que se ha compartido, es decir, que hay varios tipos de “parámetros” para una solicitud, y debe tener esto en cuenta.

  1. Localizadores: por ejemplo, identificadores de recursos como ID o acción / vista
  2. Filtros: por ejemplo, parámetros que proporcionan una búsqueda, clasificación o reducción del conjunto de resultados.
  3. Estado: por ejemplo, identificación de sesión, claves de API, whatevs.
  4. Contenido: por ejemplo, datos que se almacenarán.

Ahora veamos los diferentes lugares donde podrían ir estos parámetros.

  1. Solicitar encabezados y cookies
  2. Cadena de consulta URL (“GET” vars)
  3. Rutas URL
  4. Cadena de consulta del cuerpo / multiparte (vars “POST”)

En general, desea que el Estado se establezca en encabezados o cookies, según el tipo de información de estado que sea. Creo que todos podemos estar de acuerdo en esto. Use encabezados http personalizados (X-My-Header) si lo necesita.

De forma similar, el contenido solo tiene un lugar al que pertenecer, que se encuentra en el cuerpo de la solicitud, ya sea como cadenas de consulta o como http multiparte y / o contenido JSON. Esto es coherente con lo que recibe del servidor cuando le envía contenido. Entonces no deberías ser grosero y hacerlo de manera diferente.

Los localizadores como “id = 5” o “action = refresh” o “page = 2” tendrían sentido como ruta de URL, como mysite.com/article/5/page=2 donde en parte se sabe lo que cada parte se supone que significa (los conceptos básicos como artículo y 5 significan obviamente obtener los datos de tipo artículo con id 5) y parámetros adicionales se especifican como parte del URI. Pueden tener la forma de page=2 o page/2 si sabe que después de un cierto punto en el URI, las “carpetas” son pares clave-valor.

Los filtros siempre van en la cadena de consulta, porque si bien forman parte de la búsqueda de los datos correctos, solo están ahí para devolver un subconjunto o una modificación de lo que los localizadores devuelven solos. La búsqueda en mysite.com/article/?query=Obama (subconjunto) es un filtro, y también lo es /article/5?order=backwards mysite.com/article/?query=Obama /article/5?order=backwards (modificación). Piensa en lo que hace, ¡no solo cómo se llama!

Si “vista” determina el formato de salida, entonces es un filtro ( mysite.com/article/5?view=pdf ) porque devuelve una modificación del recurso encontrado en lugar de la ubicación en el recurso que queremos. Si, en cambio, decide qué parte específica del artículo veremos ( mysite.com/article/5/view=summary ), entonces es un localizador.

Recuerde, restringir un conjunto de recursos es filtrar. Localizar algo específico dentro de un recurso es localizar … duh. El filtrado de subconjuntos puede devolver cualquier cantidad de resultados (incluso 0). La localización siempre encontrará esa instancia específica de algo (si existe). El filtro de modificación devolverá los mismos datos que el localizador, excepto los modificados (si se permite dicha modificación).

Espero que esto haya ayudado a la gente a dar algunos momentos de eureka si se han perdido sobre dónde poner cosas.

Depende de un diseño. No hay reglas para URI en REST sobre HTTP (lo principal es que son únicas). A menudo se trata de la cuestión del gusto y la intuición …

Tomo el siguiente acercamiento:

  • url path-element: el recurso y su elemento de ruta forman un recorrido de directorio y un subrecurso (por ejemplo, / items / {id}, / users / items). Cuando no esté seguro, pregúntele a sus colegas, si ellos piensan que se cruzan y piensan en “otro directorio”, lo más probable es que el elemento de trayectoria sea la opción correcta.
  • parámetro url: cuando realmente no hay recorrido (los recursos de búsqueda con múltiples parámetros de consulta son un buen ejemplo para eso)

IMO los parámetros deberían ser mejores como argumentos de consulta. La URL se usa para identificar el recurso, mientras que los parámetros de consulta añadidos especifican qué parte del recurso desea, cualquier estado que el recurso debe tener, etc.

Según la implementación de REST,

1) Las variables de ruta se usan para la acción directa sobre los recursos, como un contacto o una canción ex.
OBTENGA etc / api / resource / {songid} o
GET etc / api / resource / {contactid} devolverá los datos respectivos.

2) Query perms / argument se usa para los recursos directos como metadatos de una canción ex .., GET / api / resource / {songid}? Metadata = géneros devolverá los datos de géneros para esa canción en particular.

“Pack” y POST sus datos contra el “contexto” que proporciona el universo-recurso-locator, lo que significa # 1 por el bien del localizador.

Ten en cuenta las limitaciones con # 2. Prefiero los POST al # 1.

nota: se discuten las limitaciones para

POST in ¿Hay un tamaño máximo para el contenido del parámetro POST?

GET in ¿Existe un límite en la duración de una solicitud GET? y Tamaño máximo de parámetros de URL en _GET

ps estos límites se basan en las capacidades del cliente (navegador) y el servidor (configuración).

De acuerdo con el estándar URI, la ruta es para parámetros jerárquicos y la consulta es para parámetros no jerárquicos. De c. puede ser muy subjetivo lo que es jerárquico para ti.

En situaciones en las que se asignan múltiples URI al mismo recurso, me gusta poner los parámetros necesarios para la identificación en la ruta y los parámetros necesarios para construir la representación en la consulta. (Para mí, de esta manera, es más fácil dirigir).

Por ejemplo:

  • /users/123 y /users/123?fields="name, age"
  • /users y /users?name="John"&age=30

Para la reducción del mapa me gusta usar los siguientes enfoques:

  • /users?name="John"&age=30
  • /users/name:John/age:30

Entonces depende de usted (y de su enrutador del lado del servidor) cómo construye sus URI.

nota: solo mencionar estos parámetros son parámetros de consulta. Entonces, lo que realmente está haciendo es definir un lenguaje de consulta simple. Mediante consultas complejas (que contienen operadores como y, o, mayor que, etc.), le sugiero que utilice un lenguaje de consulta ya existente. Las capacidades de las plantillas de URI son muy limitadas …

Como progtwigdor a menudo en el extremo del cliente, prefiero el argumento de consulta. Además, para mí, separa la ruta URL de los parámetros, agrega claridad y ofrece más extensibilidad. También me permite tener una lógica separada entre el edificio de URL / URI y el generador de parámetros.

Me gusta lo que dijo Manuel Aldana sobre la otra opción si hay algún tipo de árbol involucrado. Puedo ver piezas específicas del usuario que están siendo trepadas así.

No hay reglas duras y rápidas, pero la regla general desde un punto de vista puramente conceptual que me gusta usar puede resumirse brevemente así: una ruta URI (por definición) representa un recurso y los parámetros de consulta son esencialmente modificadores de ese recurso . Hasta ahora eso probablemente no ayude … Con una API REST usted tiene los principales métodos para actuar sobre un solo recurso usando GET , PUT y DELETE . Por lo tanto, si algo debe representarse en la ruta o como un parámetro puede reducirse a si esos métodos tienen sentido para la representación en cuestión. ¿Podría razonablemente PUT algo en ese camino y sería semánticamente sensato hacerlo? Por supuesto, puede PUT algo en cualquier lugar y doblar el back-end para manejarlo, pero debe poner en práctica lo que equivale a una representación del recurso real y no una versión contextualizada innecesariamente. Para colecciones, lo mismo se puede hacer con POST . Si desea agregar a una colección en particular, cuál sería una URL que tenga sentido para POST .

Esto aún deja algunas áreas grises, ya que algunos caminos podrían indicar qué cantidad de recursos para los padres corresponde a los hijos, lo cual es un tanto discrecional y depende de su uso. La única línea dura que dibuja es que cualquier tipo de representación transitiva debe hacerse usando un parámetro de consulta, ya que no tendría un recurso subyacente.

En respuesta al ejemplo del mundo real dado en la pregunta original (API de Twitter), los parámetros representan una consulta transitiva que filtra el estado de los recursos (en lugar de una jerarquía). En ese ejemplo particular, sería totalmente irrazonable agregar a la colección representada por esas restricciones, y además esa consulta no podría representarse como una ruta que tendría algún sentido en los términos de un gráfico de objetos.

La adopción de este tipo de perspectiva orientada a recursos puede mapearse fácilmente en el gráfico de objetos de su modelo de dominio e impulsar la lógica de su API hasta el punto en que todo funciona de manera muy limpia y de una manera bastante autoeducativa una vez que se aclara. El concepto también se puede aclarar alejándose de los sistemas que utilizan el enrutamiento de URL tradicional mapeado a un modelo de datos normalmente mal adaptado (es decir, un RDBMS). Apache Sling sin duda sería un buen lugar para comenzar. El concepto de despacho de objetos atravesados ​​en un sistema como Zope también proporciona un análogo más claro.

Aquí está mi opinión

Los parámetros de consulta se usan como metadatos para una solicitud. Actúan como filtro o modificador de una llamada de recursos existente.

Ejemplo:

/calendar/2014-08-08/events

debe dar eventos de calendario para ese día.

Si quieres eventos para una categoría específica

/calendar/2014-08-08/events?category=appointments

o si necesita eventos de más de 30 minutos

/calendar/2014-08-08/events?duration=30

Una prueba de fuego sería verificar si la solicitud aún puede ser servida sin un parámetro de consulta.

En general, tienden hacia el n. ° 2, como un argumento de consulta (es decir, / api / resource? Parameter = value).

Una tercera opción es publicar realmente el parámetro = valor en el cuerpo.

Esto se debe a que funciona mejor para recursos de parámetros múltiples y es más extensible para uso futuro.

No importa cuál elijas, asegúrate de elegir solo uno, no mezclar ni combinar. Eso lleva a una API confusa.

Todavía se ha omitido una “dimensión” de este tema, es muy importante: hay momentos en los que las “mejores prácticas” deben llegar a un acuerdo con la plataforma que estamos implementando o mejorando con las capacidades de REST.

Ejemplo práctico:

Muchas aplicaciones web hoy en día implementan la architecture MVC (Modelo, Vista, Controlador). Suponen que se proporciona una cierta ruta estándar, más aún cuando esas aplicaciones web incluyen una opción “Habilitar URL SEO”.

Solo por mencionar una aplicación web bastante famosa: una tienda de comercio electrónico de OpenCart. Cuando el administrador habilita las “URL de SEO” espera que dichas URL vengan en un formato MVC bastante estándar como:

 http://www.domain.tld/special-offers/list-all?limit=25 

Dónde

  • special-offers es el controlador MVC que procesará la URL (mostrando la página de ofertas especiales)

  • list-all es la acción del controlador o el nombre de la función a llamar. (*)

  • limit = 25 es una opción que indica que se mostrarán 25 elementos por página.

(*) list-all es un nombre de función ficticio que utilicé para mayor claridad. En realidad, OpenCart y la mayoría de los marcos MVC tienen una función de index predeterminada, implícita (y generalmente omitida en la URL) que se llama cuando el usuario desea que se realice una acción predeterminada. Entonces, la URL del mundo real sería:

 http://www.domain.tld/special-offers?limit=25 

Con una aplicación ahora bastante estándar o estructura estructurada similar a la anterior, a menudo obtendrá un servidor web que está optimizado para ello, que reescribe las URL para ello (la verdadera “URL no buscada” sería: http://www.domain.tld/index.php?route=special-offers/list-all&limit=25 ).

Por lo tanto, usted, como desarrollador, debe enfrentar la infraestructura existente y adaptar sus “mejores prácticas”, a menos que sea el administrador del sistema, sepa exactamente cómo modificar una configuración de reescritura de Apache / NGinx (¡esta última puede ser desagradable!) Y así en.

Por lo tanto, su API REST a menudo sería mucho mejor siguiendo los estándares de la aplicación web de referencia, tanto por coherencia como facilidad / velocidad (y, por lo tanto, ahorro de presupuesto).

Para volver al ejemplo práctico anterior, una API REST consistente sería algo con URL como:

 http://www.domain.tld/api/special-offers-list?from=15&limit=25 

o (URLs no SEO)

 http://www.domain.tld/index.php?route=api/special-offers-list?from=15&limit=25 

con una mezcla de argumentos “caminos formados” y argumentos “consulta formados”.

Veo muchas API REST que no manejan bien los parámetros. Un ejemplo que aparece a menudo es cuando el URI incluye información de identificación personal.

http://software.danielwatrous.com/design-principles-for-rest-apis/

Creo que una pregunta corolario es cuando un parámetro no debe ser un parámetro en absoluto, sino que debe moverse a HEADER o BODY de la solicitud.

Es una pregunta muy interesante.

Puede usar ambos, no hay ninguna regla estricta sobre este tema, pero el uso de variables de ruta URI tiene algunas ventajas:

  • Caché : la mayoría de los servicios de caché web en Internet no almacenan en caché la solicitud GET cuando contienen parámetros de consulta. Lo hacen porque hay muchos sistemas RPC que utilizan solicitudes GET para cambiar datos en el servidor (¡falla! Get debe ser un método seguro)

Pero si usa variables de ruta, todos estos servicios pueden almacenar en caché sus solicitudes GET.

  • Jerarquía : las variables de ruta pueden representar una jerarquía: / Ciudad / Calle / Lugar

Le da al usuario más información sobre la estructura de los datos.

Pero si sus datos no tienen ninguna relación jerárquica, puede usar variables de ruta, usando coma o punto y coma:

/ Ciudad / longitud, latitud

Como regla general, use una coma cuando el orden de los parámetros sea importante, use punto y coma cuando el orden no importe:

/ IconGenerator / red; azul; verde

Además de esas razones, hay algunos casos en los que es muy común usar variables de cadena de consulta:

  • Cuando necesita que el navegador coloque automáticamente variables de formulario HTML en el URI
  • Cuando se trata de algoritmo. Por ejemplo, el motor de google utiliza cadenas de consulta:

http: // http://www.google.com/search?q=rest

En resumen, no hay ninguna razón sólida para utilizar uno de estos métodos, pero siempre que sea posible, use las variables de URI.