sirve - API REST Práctica recomendada: cómo aceptar la lista de valores de parámetros como entrada
rest api example (6)
Estamos lanzando una nueva API REST y quería algunos comentarios de la comunidad sobre las mejores prácticas en cuanto a cómo deberíamos formatear los parámetros de entrada:
En este momento, nuestra API está muy centrada en JSON (solo devuelve JSON). El debate sobre si queremos / necesitamos devolver XML es un tema aparte.
Como nuestra salida de API está centrada en JSON, hemos ido por un camino en el que nuestras entradas están un poco centradas en JSON y he estado pensando que puede ser conveniente para algunos pero extraño en general.
Por ejemplo, para obtener algunos detalles del producto donde se pueden extraer múltiples productos a la vez, actualmente tenemos:
http://our.api.com/Product?id=["101404","7267261"]
Debemos simplificar esto como:
http://our.api.com/Product?id=101404,7267261
¿O es tener entrada JSON a mano? Más de un dolor?
Podemos querer aceptar ambos estilos, pero ¿esa flexibilidad realmente causa más confusión y dolores de cabeza (mantenibilidad, documentación, etc.)?
Un caso más complejo es cuando queremos ofrecer insumos más complejos. Por ejemplo, si queremos permitir múltiples filtros en la búsqueda:
http://our.api.com/Search?term=pumas&filters={"productType":["Clothing","Bags"],"color":["Black","Red"]}
No necesariamente queremos colocar los tipos de filtro (por ejemplo, productType y color) como nombres de solicitud como este:
http://our.api.com/Search?term=pumas&productType=["Clothing","Bags"]&color=["Black","Red"]
Porque queríamos agrupar todos los filtros de entrada juntos.
Al final, ¿esto realmente importa? Es probable que haya tantas utilidades JSON por ahí que el tipo de entrada simplemente no importa mucho.
Sé que nuestros clientes de JavaScript que hacen llamadas AJAX a la API pueden apreciar las entradas JSON para hacerles la vida más fácil.
Un paso atrás
En primer lugar, REST describe una URI como una ID única universal. Demasiadas personas quedan atrapadas en la estructura de las URI y cuáles URI son más "tranquilas" que otras. Este argumento es tan ridículo como decir que nombrar a alguien "Bob" es mejor que llamarlo "Joe"; ambos nombres hacen el trabajo de "identificar a una persona". Un URI no es más que un nombre universalmente único .
Entonces, a los ojos de REST, discutir sobre si ?id=["101404","7267261"]
es más reparador que ?id=101404,7267261
o /Product/101404,7267261
es algo inútil.
Ahora, dicho esto, muchas veces la forma en que se construyen los URI generalmente puede servir como un buen indicador para otros problemas en un servicio RESTful. Hay un par de banderas rojas en sus URI y preguntas en general.
Sugerencias
Múltiples URI para el mismo recurso y
Content-Location
Podemos querer aceptar ambos estilos, pero ¿esa flexibilidad realmente causa más confusión y dolores de cabeza (mantenibilidad, documentación, etc.)?
Los URI identifican los recursos. Cada recurso debe tener una URI canónica. Esto no significa que no pueda tener dos URI que apunten al mismo recurso, pero hay formas bien definidas de hacerlo. Si decide utilizar los formatos basados en JSON y en la lista (o cualquier otro formato), debe decidir cuál de estos formatos es el URI canónico principal. Todas las respuestas a otros URI que apuntan al mismo "recurso" deben incluir el encabezado de
Content-Location
.Seguir con la analogía del nombre, tener múltiples URI es como tener apodos para las personas. Es perfectamente aceptable y, a menudo, bastante práctico, sin embargo, si uso un apodo, probablemente aún quiera saber su nombre completo, la forma "oficial" de referirme a esa persona. De esta manera, cuando alguien menciona a alguien por su nombre completo, "Nichloas Telsa", sé que están hablando de la misma persona a la que llamo "Nick".
"Busca" en tu URI
Un caso más complejo es cuando queremos ofrecer insumos más complejos. Por ejemplo, si queremos permitir múltiples filtros en la búsqueda ...
Una regla general es que, si su URI contiene un verbo, puede ser una indicación de que algo está apagado. Los URI identifican un recurso, sin embargo, no deberían indicar lo que estamos haciendo con ese recurso. Ese es el trabajo de HTTP o en términos de tranquilidad, nuestra "interfaz uniforme".
Para vencer la analogía del nombre muerto, usar un verbo en una URI es como cambiar el nombre de alguien cuando quieres interactuar con ellos. Si estoy interactuando con Bob, el nombre de Bob no se convierte en "BobHi" cuando quiero saludarlo. De manera similar, cuando queremos "buscar" Productos, nuestra estructura de URI no debería cambiar de "/ Producto / ..." a "/ Buscar / ...".
Respondiendo a tu pregunta inicial
Respecto a
["101404","7267261"]
vs101404,7267261
: Mi sugerencia aquí es evitar la sintaxis JSON por razones de simplicidad (es decir, no es necesario que los usuarios realicen la codificación de URL cuando realmente no es necesario). Hará su API un poco más utilizable. Mejor aún, como han recomendado otros, vaya con el formato deapplication/x-www-form-urlencoded
estándarapplication/x-www-form-urlencoded
ya que probablemente sea más familiar para sus usuarios finales (por ejemplo?id[]=101404&id[]=7267261
). Puede que no sea "bonita", pero las URI bonitas no necesariamente significan URI utilizables. Sin embargo, para reiterar mi punto inicial, al final, cuando se habla de REST, no importa. No te detengas demasiado en ello.Su ejemplo de URI de búsqueda compleja se puede resolver de la misma manera que su ejemplo de producto. Recomendaría volver a
application/x-www-form-urlencoded
laapplication/x-www-form-urlencoded
format ya que ya es un estándar con el que muchos están familiarizados. Además, recomendaría fusionar los dos.
Su URI ...
/Search?term=pumas&filters={"productType":["Clothing","Bags"],"color":["Black","Red"]}
Su URI después de ser codificado URI ...
/Search?term=pumas&filters=%7B%22productType%22%3A%5B%22Clothing%22%2C%22Bags%22%5D%2C%22color%22%3A%5B%22Black%22%2C%22Red%22%5D%7D
Se puede transformar a ...
/Product?term=pumas&productType[]=Clothing&productType[]=Bags&color[]=Black&color[]=Red
Además de evitar el requisito de codificación de URL y hacer que las cosas se vean un poco más estándar, ahora homogeneiza un poco la API. El usuario sabe que si desea recuperar un producto o una lista de productos (ambos se consideran un "recurso" único en términos RESTful), están interesados en los URI de /Product/...
Es posible que desee revisar RFC 6570 . Esta especificación de plantilla URI muestra muchos ejemplos de cómo las URL pueden contener parámetros.
La forma estándar de pasar una lista de valores como parámetros de URL es repetirlos:
http://our.api.com/Product?id=101404&id=7267261
La mayoría de los códigos de servidor interpretarán esto como una lista de valores, aunque muchos tienen simplificaciones de valores únicos, por lo que es posible que tenga que buscar.
Los valores delimitados también están bien.
Si necesita enviar JSON al servidor, no me gusta verlo en la URL (que es un formato diferente). En particular, las URL tienen una limitación de tamaño (en la práctica, si no en teoría).
La forma en que he visto a algunos hacer una consulta complicada SÓLO en dos pasos:
-
POST
sus requisitos de consulta y reciba una ID (esencialmente creando un recurso de criterios de búsqueda) -
GET
la búsqueda, haciendo referencia a la ID anterior - opcionalmente, ELIMINE los requisitos de consulta si es necesario, pero tenga en cuenta que los requisitos están disponibles para su reutilización.
Me apoyaré con la respuesta de nategood, ya que está completa y parece haber satisfecho sus necesidades. Sin embargo, me gustaría agregar un comentario sobre la identificación de recursos múltiples (1 o más) de esa manera:
http://our.api.com/Product/101404,7267261
Al hacerlo, usted:
Compleja a los clientes forzándolos a interpretar tu respuesta como una matriz, lo que para mí es contrario a la intuición si hago la siguiente solicitud: http://our.api.com/Product/101404
Cree APIs redundantes con una API para obtener todos los productos y la anterior para obtener 1 o muchos. Dado que no debe mostrar más de 1 página de detalles a un usuario por UX, creo que tener más de 1 ID sería inútil y se usaría únicamente para filtrar los productos.
Puede que no sea tan problemático, pero tendrá que manejarlo usted mismo del lado del servidor devolviendo una sola entidad (verificando si su respuesta contiene uno o más) o permitir que los clientes la administren.
Ejemplo
Quiero pedir un libro de Amazing . Sé exactamente qué libro es y lo veo en la lista cuando navego por los libros de Horror:
- 10 000 líneas increíbles, 0 prueba increíble
- El regreso del increíble monstruo.
- Vamos a duplicar código asombroso
- El asombroso comienzo del fin.
Después de seleccionar el segundo libro, me redireccionan a una página que detalla la parte del libro de una lista:
--------------------------------------------
Book #1
--------------------------------------------
Title: The return of the amazing monster
Summary:
Pages:
Publisher:
--------------------------------------------
¿O en una página que me da los detalles completos de ese libro solamente?
---------------------------------
The return of the amazing monster
---------------------------------
Summary:
Pages:
Publisher:
---------------------------------
Mi opinión
Sugeriría usar el ID en la variable de ruta cuando la unicidad esté garantizada al obtener los detalles de este recurso. Por ejemplo, las API a continuación sugieren múltiples formas de obtener los detalles de un recurso específico (asumiendo que un producto tiene una ID única y una especificación para ese producto tiene un nombre único y puede navegar de arriba hacia abajo):
/products/{id}
/products/{id}/specs/{name}
En el momento en que necesite más de 1 recurso, sugeriría filtrar desde una colección más grande. Para el mismo ejemplo:
/products?ids=
Por supuesto, esta es mi opinión ya que no se impone.
Primer caso:
Una búsqueda de producto normal se vería así
http://our.api.com/product/1
Así que estoy pensando que la mejor práctica sería que hicieras esto
http://our.api.com/Product/101404,7267261
Segundo caso
Buscar con parámetros de cadena de consulta - así de bien. Estaría tentado de combinar los términos con AND y OR en lugar de usar []
.
PS Esto puede ser subjetivo, así que haz con lo que te sientas cómodo.
La razón para colocar los datos en la url es que el enlace pueda pegarse en un sitio / compartido entre usuarios. Si esto no es un problema, use un JSON / POST en su lugar.
EDIT: en la reflexión, creo que este enfoque se adapta a una entidad con una clave compuesta, pero no una consulta para múltiples entidades.
Primero:
Creo que puedes hacerlo de 2 maneras.
http://our.api.com/Product/<id>
: si solo desea un registro
http://our.api.com/Product
: si desea todos los registros
http://our.api.com/Product/<id1>,<id2>
: como James sugirió puede ser una opción ya que lo que viene después de la etiqueta del producto es un parámetro
O el que más me gusta es:
Puede usar la propiedad Hypermedia como motor del estado de la aplicación (HATEOAS) de un RestFul WS y hacer una llamada a http://our.api.com/Product
que debe devolver las direcciones URL equivalentes de http://our.api.com/Product/<id>
y llámalos después de esto.
Segundo
Cuando tienes que hacer consultas en las llamadas url. Sugeriría usar HATEOAS nuevamente.
1) Haga una llamada a http://our.api.com/term/pumas/productType/clothing/color/black
2) Haga una llamada a http://our.api.com/term/pumas/productType/clothing,bags/color/black,red
3) (Usando HATEOAS) Haga una llamada a ` http://our.api.com/term/pumas/productType/ -> reciba las URL todas las URL de ropa posibles -> llame a las que desea (ropa y bolsos) - > Recibe las posibles urls de colores -> llama a las que quieras