que - rest api tutorial español
¿Cómo diseñar búsqueda/filtrado RESTful? (7)
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 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 su lugar 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 ofrece grandes posibilidades para configurar filtros complejos.
De todos modos, file_get_contents(''php://input'')
no devolvió el cuerpo de la solicitud para las solicitudes GET
. También probé 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 debe tener un cuerpo de solicitud. Fue un poco concluyente, pero desaconsejaron.
Así que ahora no estoy seguro de qué hacer. ¿Cómo diseñas una función RESTful search / filterng?
Supongo que podría usar POST
, pero eso no parece muy REST.
Como uso un backend de laravel / php , tiendo a ir con algo como esto:
/resource?filters[status_id]=1&filters[city]=Sydney&page=2&include=relatedResource
PHP automáticamente convierte []
params en una matriz, por lo que en este ejemplo terminaré con una variable $filter
que contiene una matriz / objeto de filtros, junto con una página y los recursos relacionados que quiero que estén cargados.
Si usa otro idioma, esta podría ser una buena convención y puede crear un analizador para convertir []
en una matriz.
Creo que debería ir con los parámetros de solicitud, pero solo mientras no haya un encabezado HTTP adecuado para lograr lo que quiere hacer. La especificación HTTP no dice explícitamente que GET no puede tener un cuerpo. Sin embargo, este documento dice:
Por convención, cuando se utiliza el método GET, toda la información necesaria para identificar el recurso se codifica en el URI. No hay ninguna convención en HTTP / 1.1 para una interacción segura (por ejemplo, recuperación) donde el cliente suministra datos al servidor en un cuerpo de entidad HTTP en lugar de en la parte de consulta de un URI. Esto significa que para operaciones seguras, los URI pueden ser largos.
FYI: Sé que esto es un poco tarde pero para cualquiera que esté interesado. Dependiendo de la forma en que RESTful quiera ser, tendrá que implementar sus propias estrategias de filtrado, ya que la especificación de HTTP no es muy clara al respecto. Me gustaría sugerir la codificación url de todos los parámetros del filtro, por ejemplo
GET api/users?filter=param1%3Dvalue1%26param2%3Dvalue2
Sé que es feo, pero creo que es la forma más RESTABLECIDA de hacerlo y debería ser fácil de analizar en el lado del servidor :)
La mejor manera de implementar una búsqueda REST es considerar que la búsqueda en sí misma es un recurso. Luego puedes usar el verbo POST porque estás creando una búsqueda. No es necesario que, literalmente, cree algo en una base de datos para utilizar un POST.
Por ejemplo:
Accept: application/json
Content-Type: application/json
POST http://example.com/people/searches
{
"terms": {
"ssn": "123456789"
},
"order": { ... },
...
}
Estás creando una búsqueda desde el punto de vista del usuario. Los detalles de implementación de esto son irrelevantes. Algunas API RESTful pueden incluso no necesitar persistencia. Ese es un detalle de implementación.
No se preocupe demasiado si su API inicial es completamente REST o no (especialmente cuando solo está en las etapas alfa). Obtener la tubería de fondo para trabajar primero. Siempre puede hacer algún tipo de transformación / reescritura de URL para mapear las cosas, refinándolas de forma iterativa hasta que obtenga algo lo suficientemente estable como para una prueba generalizada ("beta").
Puede definir URI cuyos parámetros están codificados por posición y convención en los URI en sí mismos, con el prefijo de una ruta que sabe que siempre asignará a algo. No sé PHP, pero supongo que existe tal facilidad (como existe en otros idiomas con marcos web):
.es decir. Haga un tipo de búsqueda de "usuario" con param [i] = valor [i] para i = 1..4 en la tienda # 1 (con value1, value2, value3, ... como una abreviatura de los parámetros de consulta de URI):
1) GET /store1/search/user/value1,value2,value3,value4
o
2) GET /store1/search/user,value1,value2,value3,value4
o como sigue (aunque no lo recomendaría, más adelante)
3) GET /search/store1,user,value1,value2,value3,value4
Con la opción 1, /store1/search/user
todos los URI con el prefijo /store1/search/user
al manejador de búsqueda (o la designación de PHP) que realiza la búsqueda 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, el user
) como parámetro posicional # 1. Cualquiera de las opciones es solo una opción cosmética.
La opción 3 también es posible, pero no creo que me guste. Creo que la capacidad de búsqueda dentro de ciertos recursos debe presentarse en el URI en sí, antes de la búsqueda en sí misma (como si indicara claramente en el URI que la búsqueda es específica dentro del recurso).
La ventaja de esta superación de los parámetros en el URI es que la búsqueda es parte del URI (por lo tanto, se trata de una búsqueda como un recurso, un recurso cuyo contenido puede (y será) cambiar con el tiempo). La desventaja es que el orden de los parámetros es obligatorio .
Una vez que hagas algo como esto, puedes usar GET, y sería un recurso de solo lectura (ya que no puedes POST o PUT), se actualiza cuando se GET''ed). También sería un recurso que solo existe cuando se invoca.
También se podría agregar más semántica almacenando en caché los resultados durante un período de tiempo o con un BORRADO que haga que se elimine la memoria caché. Sin embargo, esto puede ir en contra de lo que las personas suelen utilizar DELETE (y porque las personas normalmente controlan el almacenamiento en caché con encabezados de almacenamiento en caché).
Cómo lo hagas sería una decisión de diseño, pero esta sería la forma en que yo lo haría. No es perfecto, y estoy seguro de que habrá casos en los que hacer esto no es lo mejor (especialmente para criterios de búsqueda muy complejos).
Parece que el filtrado / búsqueda de recursos se puede implementar de forma REST completa. 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 el método POST
. De esta manera, por supuesto, el cuerpo se puede usar para transportar todos los parámetros, así como también se pueden crear complejas estructuras 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 única junto con el código de estado
201 Created
. Luego, utilizando este ID, se puede hacer una solicitudGET
a/api/users/
like:GET /api/users/?filterId=1234-abcd
Después de que se crea un nuevo filtro a través de
POST
, no responderá con201 Created
pero de inmediato con303 SeeOther
junto con el encabezado deLocation
apunta a/api/users/?filterId=1234-abcd
. Esta redirección se manejará 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 las aplicaciones móviles. Para aplicaciones móviles, usaría una sola llamada POST
a /api/users/filter/
.
¿Cómo mantener los filtros creados?
Se pueden almacenar en DB y utilizar más tarde. También pueden almacenarse en algún almacenamiento temporal, por ejemplo, redis y tener algunos TTL, después de lo cual expirará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 marcar como favoritos.
Si usa el cuerpo de la solicitud en una solicitud GET, está rompiendo el principio REST, porque su solicitud GET no podrá ser almacenada en caché, porque el sistema de caché usa solo la URL.
Y lo que es peor, su URL no se puede marcar, porque la URL no contiene toda la información necesaria para redirigir al usuario a esta página
Utilice los parámetros de URL o consulta en lugar de los parámetros del cuerpo de la solicitud.
p.ej:
/myapp?var1=xxxx&var2=xxxx
/myapp;var1=xxxx/resource;var2=xxxx
De hecho, el HTTP RFC 7231 dice que:
Una carga útil dentro de un mensaje de solicitud GET no tiene una semántica definida; enviar un cuerpo de carga útil en una solicitud GET puede hacer que algunas implementaciones existentes rechacen la solicitud.
Para más información echar un vistazo here