¿Cuándo uso los parámetros de ruta frente a los parámetros de consulta en una API RESTful?

141

Quiero hacer que mi API RESTful sea muy predecible. ¿Cuál es la mejor práctica para decidir cuándo hacer una segmentación de datos utilizando el URI en lugar de utilizar parámetros de consulta?

Para mí tiene sentido que los parámetros del sistema que admiten la paginación, la clasificación y la agrupación estén después del '?' Pero, ¿qué pasa con los campos como 'estado' y 'región' u otros atributos que segmentan su colección? Si también van a ser parámetros de consulta, ¿cuál es la regla general para saber cuándo usar parámetros de ruta?

cosbor11
fuente
1
aquí se responde una pregunta similar ... stackoverflow.com/questions/3198492/…
Lalit Mehra

Respuestas:

239

La mejor práctica para el diseño de RESTful API es que los parámetros de ruta se usan para identificar un recurso o recursos específicos, mientras que los parámetros de consulta se usan para ordenar / filtrar esos recursos.

Aquí hay un ejemplo. Suponga que está implementando puntos finales API RESTful para una entidad llamada Car. Estructurarías tus puntos finales de esta manera:

GET /cars
GET /cars/:id
la POST /cars
PUT /cars/:id
DELETE/cars/:id

De esta forma, solo está utilizando parámetros de ruta cuando especifica qué recurso buscar, pero esto no clasifica / filtra los recursos de ninguna manera.

Ahora suponga que desea agregar la capacidad de filtrar los automóviles por color en sus solicitudes GET. Como el color no es un recurso (es una propiedad de un recurso), puede agregar un parámetro de consulta que lo haga. Agregaría ese parámetro de consulta a su solicitud GET de/cars esta manera:

OBTENER /cars?color=blue

Este punto final se implementaría para que solo se devolvieran los automóviles azules.

En lo que respecta a la sintaxis, sus nombres de URL deben estar en minúsculas. Si tiene un nombre de entidad que generalmente tiene dos palabras en inglés, usaría un guión para separar las palabras, no el caso de camello.

Ex. /two-words

Miguel
fuente
3
Gracias por tu respuesta Mike. Esta es una metodología clara y simple; Vale la pena un voto de mi parte. Aún así, a menudo, los desarrolladores optan por el enfoque 'autos / azul', me pregunto cuál es su razonamiento para hacerlo ... tal vez deciden hacer parámetros de ruta para campos que son obligatorios, o tal vez lo hacen para indicar que la base de datos está particionada por ese fragmento.
cosbor11
1
No estoy seguro de cuál es su razonamiento. Honestamente, no estoy de acuerdo con eso. Creo que seguir las convenciones y mantenerlo simple tiene más sentido. Al hacerlo, permite que los consumidores de su API comprendan mejor exactamente lo que necesitan hacer para acceder a su funcionalidad.
Mike
3
¿Qué pasa con / cars? id = 1 & color = blue en lugar de cars / 1 /? color = blue. básicamente está filtrando recursos de automóviles en cada escenario
mko
1
Incorrecto ya que el automóvil con id 1 solo existe uno, pero los automóviles con color azul pueden ser muchos. Existe la distinción entre identidad y filtro
Paul
1
Mi hipótesis de por qué el uso de parámetros de ruta está tan extendido se debe a que muchos desarrolladores aprendieron de los marcos diseñados por personas que no tenían una buena comprensión de los principios REST (Ruby on Rails en particular)
Chris Broski,
58

La forma fundamental de pensar sobre este tema es la siguiente:

Un URI es un identificador de recurso que identifica de forma exclusiva una instancia específica de un TIPO de recurso. Como todo lo demás en la vida, cada objeto (que es una instancia de algún tipo), tiene un conjunto de atributos que son temporales o temporales.

En el ejemplo anterior, un automóvil es un objeto muy tangible que tiene atributos como marca, modelo y VIN, que nunca cambia, y color, suspensión, etc. que pueden cambiar con el tiempo. Entonces, si codificamos el URI con atributos que pueden cambiar con el tiempo (temporal), podemos terminar con múltiples URI para el mismo objeto:

GET /cars/honda/civic/coupe/{vin}/{color=red}

Y años después, si el color de este mismo automóvil cambia a negro:

GET /cars/honda/civic/coupe/{vin}/{color=black}

Tenga en cuenta que la instancia del automóvil en sí (el objeto) no ha cambiado, solo cambió el color. Tener múltiples URI apuntando a la misma instancia de objeto lo obligará a crear múltiples manejadores de URI; este no es un diseño eficiente y, por supuesto, no es intuitivo.

Por lo tanto, el URI solo debe constar de partes que nunca cambiarán y continuarán identificando de manera única ese recurso durante toda su vida útil. Todo lo que pueda cambiar debe reservarse para los parámetros de consulta, como tal:

GET /cars/honda/civic/coupe/{vin}?color={black}

En pocas palabras: piense en el polimorfismo.

Kingz
fuente
2
Paradigma interesante. ¿Es este un patrón de diseño de uso común? ¿Puede proporcionar algunas API que utilicen esto en su documentación o algunas referencias que describan esta estrategia?
cosbor11
1
Me gusta cómo enfatizaste "TIPO" cuando escribiste "Un URI es un identificador de recurso que identifica de forma única una instancia específica de un TIPO de recurso". Creo que es una distinción importante.
jrahhali
15

En una API REST, no debe preocuparse demasiado por los URI predecibles. La sugerencia misma de la previsibilidad de URI alude a un malentendido de la arquitectura RESTful. Se supone que un cliente debería estar construyendo URI por sí mismo, algo que realmente no debería ser necesario.

Sin embargo, supongo que no está creando una verdadera API REST, sino una API 'inspirada en REST' (como la de Google Drive). En estos casos, la regla general es 'parámetros de ruta = identificación de recursos' y 'parámetros de consulta = clasificación de recursos'. Entonces, la pregunta es, ¿puede identificar de manera única su recurso SIN estado / región? Si es así, entonces quizás sea un parámetro de consulta. Si no, entonces es un camino param.

HTH

Oliver McPhee
fuente
11
No estoy de acuerdo, una buena API debería ser predecible; RESTANTE o de otra manera.
cosbor11
3
Creo que sí. Debería haber rima y razón sobre cómo se forma el URI, en lugar de nombrar puntos finales arbitrariamente. Cuando uno puede escribir intuitivamente un cliente API sin hacer referencia constante a la documentación, en mi opinión, ha escrito una buena API.
cosbor11 01 de
2
"Cuando uno puede escribir intuitivamente un cliente API sin hacer referencia constante a la documentación". Ahí es donde creo que nuestra comprensión de REST difiere ... el cliente API nunca debería necesitar 'construir' una URL. Deben seleccionarlo de la respuesta de la llamada API anterior. Si toma un sitio web como analogía ... Vaya a facebook.com, luego seleccione un enlace a la página de eventos. No le importa si la URL de eventos de Facebook es 'predecible', ya que no la está escribiendo. Llega a través de enlaces de hipermedia. Lo mismo es cierto para una API REST. Entonces, haga que los URI sean significativos para usted (el servidor), pero no para el cliente
Oliver McPhee
2
Nota añadida Esto no significa que los URI no deban seguir un patrón fácil de entender, solo significa que no es una restricción de una API RESTful. El mayor problema con esta área es que las personas suponen que un cliente debe construir las URL por sí mismo. No deberían, ya que eso crea un acoplamiento entre el cliente y el servidor que no debería existir. (por ejemplo, el servidor no puede cambiar una URL sin romper todas las aplicaciones cliente). En una API REST, el servidor puede cambiarlos como lo desee.
Oliver McPhee
3
+1 por usar las siguientes palabras: "'parámetros de ruta = identificación de recursos' y 'parámetros de consulta = clasificación de recursos'". Esto realmente me lo aclaró.
Doug
3

Una vez que diseñé una API, que recurso principal era people. Por lo general, los usuarios solicitarían un filtro filtrado people, para evitar que los usuarios llamaran algo así /people?settlement=urbancada vez que lo implementaba, lo /people/urbanque luego me permitió agregar fácilmente /people/rural. Además, esto permite acceder a la /peoplelista completa si sería de alguna utilidad más adelante. En resumen, mi razonamiento fue agregar una ruta a subconjuntos comunes

Desde aquí :

Alias ​​para consultas comunes

Para que la experiencia API sea más agradable para el consumidor promedio, considere empaquetar conjuntos de condiciones en rutas RESTful de fácil acceso. Por ejemplo, la consulta anterior de tickets recientemente cerrada podría empaquetarse comoGET /tickets/recently_closed

Mario Gil
fuente
1

En términos generales, tiendo a usar parámetros de ruta cuando hay una 'jerarquía' obvia en el recurso, como:

/region/state/42

Si ese único recurso tiene un estado, uno podría:

/region/state/42/status

Sin embargo, si 'región' no es realmente parte del recurso expuesto, probablemente pertenece como uno de los parámetros de consulta, similar a la paginación (como mencionó).

morsor
fuente
0

La segmentación es más jerárquica y "bonita" pero puede ser limitante.

Por ejemplo, si tiene una url con tres segmentos, cada uno pasa parámetros diferentes para buscar un automóvil por marca, modelo y color:

www.example.com/search/honda/civic/blue

Esta es una url muy bonita y más fácil de recordar por el usuario final, pero ahora te quedas con esta estructura. Digamos que quiere hacerlo para que en la búsqueda el usuario pueda buscar TODOS los autos azules o TODOS los Honda Civics. Un parámetro de consulta resuelve esto porque da un par de valores clave. Para que puedas pasar:

www.example.com/search?color=blue
www.example.com/search?make=civic

Ahora tiene una manera de hacer referencia al valor a través de su clave: "color" o "make" en su código de consulta.

Podría solucionar esto posiblemente utilizando más segmentos para crear una especie de estructura de valores clave como:

www.example.com/search/make/honda/model/civic/color/blue

Espero que tenga sentido ...

webmaster_sean
fuente
-2

URL de ejemplo: /rest/{keyword}

Esta URL es un ejemplo de parámetros de ruta. Podemos obtener estos datos de URL usando@PathParam .

URL de ejemplo: /rest?keyword=java&limit=10

Esta URL es un ejemplo para los parámetros de consulta. Podemos obtener estos datos de URL usando @Queryparam.

Sujithrao
fuente