Actualmente estoy diseñando e implementando una API RESTful en PHP. Sin embargo, no he podido implementar mi diseño inicial.
GET /users # list of users
GET /user/1 # get user with id 1
POST /user # create new user
PUT /user/1 # modify user with id 1
DELETE /user/1 # delete user with id 1
Hasta ahora bastante estándar, ¿verdad?
Mi problema es con el primero GET /users
. Estaba considerando enviar parámetros en el cuerpo de la solicitud para filtrar la lista. Esto se debe a que quiero poder especificar filtros complejos sin obtener una URL muy larga, como:
GET /users?parameter1=value1¶meter2=value2¶meter3=value3¶meter4=value4
En cambio, quería tener algo como:
GET /users
# Request body:
{
"parameter1": "value1",
"parameter2": "value2",
"parameter3": "value3",
"parameter4": "value4"
}
que es mucho más legible y le brinda grandes posibilidades para configurar filtros complejos.
De todos modos, file_get_contents('php://input')
no devolvió el cuerpo de la GET
solicitud para las solicitudes. También lo intenté http_get_request_body()
, pero el alojamiento compartido que estoy usando no tiene pecl_http
. No estoy seguro de que hubiera ayudado de todos modos.
Encontré esta pregunta y me di cuenta de que GET probablemente no debería tener un cuerpo de solicitud. Fue un poco inconcluso, pero desaconsejaron.
Así que ahora no estoy seguro de qué hacer. ¿Cómo se diseña una función de búsqueda / filtrado RESTful?
Supongo que podría usar POST
, pero eso no parece muy RESTANTE.
Respuestas:
La mejor manera de implementar una búsqueda RESTful es considerar la búsqueda en sí misma como un recurso. Luego puede usar el verbo POST porque está creando una búsqueda. No tiene que crear literalmente algo en una base de datos para utilizar una POST.
Por ejemplo:
Está creando una búsqueda desde el punto de vista del usuario. Los detalles de implementación de esto son irrelevantes. Es posible que algunas API RESTful ni siquiera necesiten persistencia. Ese es un detalle de implementación.
fuente
Si usa el cuerpo de la solicitud en una solicitud GET, está rompiendo el principio REST, porque su solicitud GET no podrá almacenarse en caché, porque el sistema de caché usa solo la URL.
Y lo que es peor, su URL no se puede agregar a favoritos, porque la URL no contiene toda la información necesaria para redirigir al usuario a esta página
Utilice los parámetros URL o Consulta en lugar de los parámetros del cuerpo de la solicitud.
p.ej:
De hecho, el HTTP RFC 7231 dice que:
Una carga útil dentro de un mensaje de solicitud GET no tiene semántica definida; El envío de un cuerpo de carga útil en una solicitud GET puede causar que algunas implementaciones existentes rechacen la solicitud.
Para más información mira aquí
fuente
Parece que el filtrado / búsqueda de recursos puede implementarse de una manera RESTful. La idea es introducir un nuevo punto final llamado
/filters/
o/api/filters/
.El uso de este filtro de punto final se puede considerar como un recurso y, por lo tanto, se puede crear mediante un
POST
método. De esta forma, por supuesto, el cuerpo se puede usar para transportar todos los parámetros, así como también se pueden crear estructuras complejas de búsqueda / filtro.Después de crear dicho filtro, hay dos posibilidades para obtener el resultado de búsqueda / filtro.
Se devolverá un nuevo recurso con ID único junto con el
201 Created
código de estado. Luego, utilizando esta ID,GET
se puede hacer una solicitud para que le/api/users/
guste:Después de crear un nuevo filtro a través de
POST
él, no responderá con,201 Created
pero de inmediato con303 SeeOther
junto con elLocation
encabezado apuntando a/api/users/?filterId=1234-abcd
. Esta redirección se gestionará automáticamente a través de la biblioteca subyacente.En ambos escenarios, se deben realizar dos solicitudes para obtener los resultados filtrados; esto puede considerarse como un inconveniente, especialmente para aplicaciones móviles. Para aplicaciones móviles, usaría una sola
POST
llamada a/api/users/filter/
.¿Cómo mantener los filtros creados?
Se pueden almacenar en DB y usar más adelante. También se pueden almacenar en algún almacenamiento temporal, por ejemplo, redis y tienen algo de TTL, después de lo cual caducarán y se eliminarán.
¿Cuáles son las ventajas de esta idea?
Los filtros, los resultados filtrados se pueden almacenar en caché e incluso se pueden agregar a favoritos.
fuente
Creo que debería ir con los parámetros de solicitud, pero solo mientras no haya un encabezado HTTP apropiado para lograr lo que desea hacer. La especificación HTTP no dice explícitamente que GET no puede tener un cuerpo. Sin embargo, este documento establece:
fuente
Como estoy usando un backend laravel / php tiendo a ir con algo como esto:
PHP convierte automáticamente los
[]
parámetros en una matriz, por lo que en este ejemplo terminaré con una$filter
variable que contiene una matriz / objeto de filtros, junto con una página y cualquier recurso relacionado que quiera cargar con ansias.Si usa otro idioma, esto podría ser una buena convención y puede crear un analizador para convertirlo
[]
en una matriz.fuente
[
y]
. Usar representaciones codificadas de estos caracteres para agrupar parámetros de consulta es una práctica bien conocida. Incluso se usa en JSON: especificación API .No se preocupe demasiado si su API inicial es completamente RESTful o no (especialmente cuando solo está en las etapas alfa). Haga que la plomería de fondo funcione primero. Siempre puede hacer algún tipo de transformación / reescritura de URL para mapear las cosas, refinando iterativamente hasta que obtenga algo lo suficientemente estable como para realizar pruebas generalizadas ("beta").
Puede definir los URI cuyos parámetros están codificados por posición y convención en los mismos URI, precedidos por una ruta que sabe que siempre asignará a algo. No conozco PHP, pero supongo que existe tal facilidad (como existe en otros idiomas con marcos web):
.es decir. Realice una búsqueda de tipo "usuario" con param [i] = value [i] para i = 1..4 en la tienda # 1 (con value1, value2, value3, ... como una abreviatura para los parámetros de consulta URI):
o
o de la siguiente manera (aunque no lo recomendaría, más sobre eso más adelante)
Con la opción 1, asigna todos los URI prefijados
/store1/search/user
al controlador de búsqueda (o la designación de PHP) de manera predeterminada para realizar búsquedas de recursos en store1 (equivalente a/search?location=store1&type=user
.Por convención documentada y aplicada por la API, los valores de los parámetros 1 a 4 están separados por comas y se presentan en ese orden.
La opción 2 agrega el tipo de búsqueda (en este caso
user
) como parámetro posicional # 1. Cualquiera de las opciones es solo una elección cosmética.La opción 3 también es posible, pero no creo que me gustaría. Creo que la capacidad de búsqueda dentro de ciertos recursos debe presentarse en el URI mismo que precede a la búsqueda en sí (como si indicara claramente en el URI que la búsqueda es específica dentro del recurso).
La ventaja de esto sobre el paso de parámetros en el URI es que la búsqueda es parte del URI (por lo tanto, trata una búsqueda como un recurso, un recurso cuyo contenido puede, y cambiará, con el tiempo). La desventaja es que el orden de los parámetros es obligatorio .
Una vez que haga algo como esto, puede usar GET, y sería un recurso de solo lectura (ya que no puede PUBLICAR ni PONER - se actualiza cuando se GET). También sería un recurso que solo llega a existir cuando se invoca.
También se podría agregar más semántica al almacenar en caché los resultados durante un período de tiempo o con un DELETE que hace que se elimine el caché. Sin embargo, esto podría ir en contra de lo que la gente suele usar DELETE (y porque las personas generalmente controlan el almacenamiento en caché con los encabezados de almacenamiento en caché).
La forma en que lo haga sería una decisión de diseño, pero esta sería la forma en que lo haría. No es perfecto, y estoy seguro de que habrá casos en los que hacer esto no sea lo mejor (especialmente para criterios de búsqueda muy complejos).
fuente
FYI: Sé que esto es un poco tarde, pero para cualquiera que esté interesado. Depende de cuán RESTful desee ser, tendrá que implementar sus propias estrategias de filtrado ya que la especificación HTTP no es muy clara al respecto. Me gustaría sugerir la codificación url de todos los parámetros de filtro, por ejemplo
Sé que es feo, pero creo que es la forma más RESTful de hacerlo y debería ser fácil de analizar en el lado del servidor :)
fuente