Estoy buscando una forma razonable de representar las búsquedas como URL RESTful.
La configuración: tengo dos modelos, Cars y Garages, donde Cars puede estar en Garages. Entonces mis URL se ven así:
/car/xxxx
xxx == car id
returns car with given id
/garage/yyy
yyy = garage id
returns garage with given id
Un automóvil puede existir solo (de ahí el / automóvil), o puede existir en un garaje. ¿Cuál es la forma correcta de representar, por ejemplo, todos los autos en un garaje determinado? Algo como:
/garage/yyy/cars ?
¿Qué tal la unión de autos en garaje yyy y zzz?
¿Cuál es la forma correcta de representar una búsqueda de automóviles con ciertos atributos? Diga: muéstrame todos los sedanes azules con 4 puertas:
/car/search?color=blue&type=sedan&doors=4
o debería ser / cars en su lugar?
El uso de "buscar" parece inapropiado allí: ¿cuál es una mejor forma / término? Debería ser solo:
/cars/?color=blue&type=sedan&doors=4
¿Deben los parámetros de búsqueda ser parte de PATHINFO o QUERYSTRING?
En resumen, estoy buscando orientación para el diseño de URL REST entre modelos y para la búsqueda.
[Actualización] Me gusta la respuesta de Justin, pero no cubre el caso de búsqueda de múltiples campos:
/cars/color:blue/type:sedan/doors:4
o algo así. ¿Cómo pasamos de
/cars/color/blue
al caso de campo múltiple?
/cars
y/car
no es semántica y por lo tanto una mala idea. Utilice siempre el plural cuando haya más de un elemento en esa categoría.Respuestas:
Para la búsqueda, use cadenas de consulta. Esto es perfectamente RESTful:
Una ventaja de las cadenas de consulta regulares es que son estándar y ampliamente entendidas, y que se pueden generar desde form-get.
fuente
/cars?color=whatever
./cars?color=blue&type=sedan&doors=4/engines
, no funcionará/cars?param=value
es para el filtrado simple en la lista de autos y/cars/search?param=value
para crear una búsqueda (sin persistencia) donde el resultado puede contener puntaje de búsqueda, categorización, etc. También puede crear / eliminar una búsqueda con nombre como/cars/search/mysearch
. Mira eso: stackoverflow.com/a/18933902/1480391El diseño de URL bonita RESTful se trata de mostrar un recurso basado en una estructura (estructura similar a un directorio, fecha: artículos / 2005/5/13, objeto y sus atributos, ..), la barra
/
indica la estructura jerárquica, use el-id
lugar.Estructura jerarquica
Yo personalmente preferiría:
Si un usuario elimina la
/car-id
pieza, trae lacars
vista previa, intuitiva. El usuario sabe exactamente en qué parte del árbol está, qué está mirando. Él sabe desde el primer vistazo, que los garajes y los automóviles están en relación./car-id
También denota que pertenece junto a diferencia/car/id
.buscando
La búsqueda está bien tal como está , solo existe su preferencia, lo que debe tenerse en cuenta. La parte divertida viene cuando se unen búsquedas (ver más abajo).
O básicamente cualquier cosa que no sea una barra como se explicó anteriormente.
La fórmula:,
/cars[?;]color[=-:]blue[,;+&]
* aunque no usaría el&
signo ya que es irreconocible del texto a primera vista.Listas de opciones
posibles características?
Negar cadenas de búsqueda (!)
Para buscar cualquier automóvil, pero no negro y rojo :
?color=!black,!red
color:(!black,!red)
Búsquedas unidas
Búsqueda rojos o azules o negras coches con 3 puertas de garajes Identificación 1..20 o 101..103 o 999 , pero no 5
/garage[id=1-20,101-103,999,!5]/cars[color=red,blue,black;doors=3]
a continuación, usted puede construir más complejas consultas de búsqueda. (Observe la coincidencia de atributos CSS3 para la idea de hacer coincidir subcadenas. Por ejemplo, buscar usuarios que contengan "barra"
user*=bar
).Conclusión
De todos modos, esta podría ser la parte más importante para usted, porque usted puede hacerlo sin embargo te gusta después de todo, sólo tener en cuenta que REST URI representa una estructura que es fácil de entender por ejemplo directory-como
/directory/file
,/collection/node/item
, fechas/articles/{year}/{month}/{day}
.. Y cuando se omite cualquiera de los últimos segmentos, inmediatamente sabes lo que obtienes.Entonces, todos estos caracteres están permitidos sin codificar :
a-zA-Z0-9_.-~
normalmente permitido tanto codificado como no, ambos usos son equivalentes.
$-_.+!*'(),
;/?:@=&
puede usar sin codificar para el propósito que representan; de lo contrario, se debe codificar.
inseguro: por
<>"#%{}|\^~[]`
qué inseguro y por qué debería codificarse: RFC 1738 ver 2.2
Consulte también RFC 1738 # página-20 para obtener más clases de caracteres.
RFC 3986 ver 2.2
A pesar de lo que dije anteriormente, aquí hay una distinción común de delimitadores, lo que significa que algunos "son" más importantes que otros.
:/?#[]@
!$&'()*+,;=
Más información:
Jerarquía: consulte 2.3 , consulte 1.2.3
sintaxis de parámetro de ruta de URL url que
coincide con el atributo CSS3
IBM: servicios web RESTful - Aspectos básicos
Nota: RFC 1738 fue actualizado por RFC 3986
fuente
POST
. Además, otras ideas que dio en su respuesta también son muy apreciables. ¡Muchas gracias!;
en lugar de&
es la legibilidad? Porque si es así, creo que preferiría el,&
ya que es el delimitador más común ... ¿verdad? :) ¡Gracias!&
como delimitador solo lo conocen los desarrolladores. Los padres, abuelos y la población no educada acepta delimitadores tal como se usan en el texto escrito común.Aunque tener los parámetros en el camino tiene algunas ventajas, existen, en mi opinión, algunos factores que superan.
No todos los caracteres necesarios para una consulta de búsqueda están permitidos en una URL. La mayoría de los signos de puntuación y Unicode tendrían que estar codificados en URL como un parámetro de cadena de consulta. Estoy luchando con el mismo problema. Me gustaría usar XPath en la URL, pero no toda la sintaxis de XPath es compatible con una ruta URI. Entonces, para rutas simples,
/cars/doors/driver/lock/combination
sería apropiado ubicar elcombination
elemento ' ' en el documento XML de la puerta del conductor. Pero/car/doors[id='driver' and lock/combination='1234']
no es tan amigable.Hay una diferencia entre filtrar un recurso en función de uno de sus atributos y especificar un recurso.
Por ejemplo, desde
/cars/colors
devuelve una lista de todos los colores para todos los automóviles (el recurso devuelto es una colección de objetos de color)/cars/colors/red,blue,green
devolvería una lista de objetos de color rojo, azul o verde, no una colección de automóviles.Para devolver los autos, el camino sería
/cars?color=red,blue,green
o/cars/search?color=red,blue,green
Los parámetros en la ruta son más difíciles de leer porque los pares de nombre / valor no están aislados del resto de la ruta, que no son pares de nombre / valor.
Un ultimo comentario. Prefiero
/garages/yyy/cars
(siempre en plural) a/garage/yyy/cars
(tal vez fue un error tipográfico en la respuesta original) porque evita cambiar la ruta entre singular y plural. Para palabras con un añadido 's', el cambio no es tan malo, pero cambiando/person/yyy/friends
de/people/yyy
parecer engorroso.fuente
Para ampliar la respuesta de Peter, puede hacer que la búsqueda sea un recurso de primera clase:
El recurso de búsqueda tendría campos para color, modelo, estado de garajes, etc. y podría especificarse en XML, JSON o cualquier otro formato. Al igual que el recurso Coche y Garaje, puede restringir el acceso a las búsquedas en función de la autenticación. Los usuarios que ejecutan con frecuencia las mismas búsquedas pueden almacenarlos en sus perfiles para que no necesiten volver a crearlos. Las URL serán lo suficientemente cortas como para que en muchos casos puedan intercambiarse fácilmente por correo electrónico. Estas búsquedas almacenadas pueden ser la base de fuentes RSS personalizadas, etc.
Existen muchas posibilidades para utilizar las búsquedas cuando las considera recursos.
La idea se explica con más detalle en este Railscast .
fuente
La respuesta de Justin es probablemente el camino a seguir, aunque en algunas aplicaciones puede tener sentido considerar una búsqueda particular como un recurso en sí mismo, como por ejemplo si desea admitir búsquedas guardadas con nombre:
o
fuente
Utilizo dos enfoques para implementar búsquedas.
1) Caso más simple, para consultar elementos asociados y para navegación.
Esto significa, consultar automóviles que tengan una ID de garaje igual a 1.
También es posible crear búsquedas más complejas:
Autos en todos los garajes en FirstStreet que no son rojos (3ra página, 100 elementos por página).
2) Las consultas complejas se consideran recursos regulares que se crean y pueden recuperarse.
El cuerpo POST para la creación de búsqueda es el siguiente:
Está basado en Grails (criterio DSL): http://grails.org/doc/2.4.3/ref/Domain%20Classes/createCriteria.html
fuente
Esto no es REST. No puede definir URI para recursos dentro de su API. La navegación de recursos debe ser impulsada por hipertexto. Está bien si desea URI bonitos y grandes cantidades de acoplamiento, pero simplemente no lo llame REST, porque viola directamente las restricciones de la arquitectura RESTful.
Ver este artículo del inventor de REST.
fuente
Aunque me gusta la respuesta de Justin, creo que representa con mayor precisión un filtro en lugar de una búsqueda. ¿Qué pasa si quiero saber sobre autos con nombres que comienzan con cam?
A mi modo de ver, puede incorporarlo a la forma en que maneja recursos específicos:
/ cars / cam *
O simplemente puede agregarlo al filtro:
/ cars / doors / 4 / name / cam * / colors / red, azul, verde
Personalmente, prefiero este último, sin embargo, de ninguna manera soy un experto en REST (lo escuché por primera vez hace solo 2 o más semanas ...)
fuente
/cars?name=cam*
RESTful no recomienda usar verbos en URL's / cars / search no es tranquilo. La forma correcta de filtrar / buscar / paginar sus API es a través de los parámetros de consulta. Sin embargo, puede haber casos en los que tenga que romper la norma. Por ejemplo, si está buscando en múltiples recursos, entonces debe usar algo como / search? Q = query
Puede visitar http://saipraveenblog.wordpress.com/2014/09/29/rest-api-best-practices/ para comprender las mejores prácticas para diseñar API RESTful
fuente
Además, también sugeriría:
Aquí,
Search
se considera como un recurso secundario deCars
recurso.fuente
Aquí hay muchas buenas opciones para su caso. Aún así, debería considerar usar el cuerpo POST.
La cadena de consulta es perfecta para su ejemplo, pero si tiene algo más complicado, por ejemplo, una larga lista arbitraria de elementos o condicionales booleanos, es posible que desee definir la publicación como un documento que el cliente envía a través de POST.
Esto permite una descripción más flexible de la búsqueda, así como también evita el límite de longitud de URL del servidor.
fuente
Mi consejo sería este:
Editar:
Esperemos que eso te de la idea. Esencialmente, su API Rest debería ser fácilmente detectable y debería permitirle navegar a través de sus datos. Otra ventaja de utilizar URL y no cadenas de consulta es que puede aprovechar los mecanismos de almacenamiento en caché nativos que existen en el servidor web para el tráfico HTTP.
Aquí hay un enlace a una página que describe los males de las cadenas de consulta en REST: http://web.archive.org/web/20070815111413/http://rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsideredHarmful
Utilicé el caché de Google porque la página normal no funcionaba para mí, aquí está ese enlace también: http://rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsideredHarmful
fuente
/cars/colors/red,blue,green
y/cars/colors/green,blue,red
? El elemento de ruta del URI debe ser jerárquico, y realmente no veo que ese sea el caso aquí. Creo que esta es una situación en la que la cadena de consulta es la opción más adecuada.