the restful practices practice microsoft guidelines good designing best rest api-design

restful - ¿Cuáles son las mejores prácticas para los recursos anidados REST?



restful api designing guidelines the best practices (6)

Por lo que puedo decir, cada recurso individual debe tener solo una ruta canónica . Entonces, en el siguiente ejemplo, ¿cuáles serían los buenos patrones de URL?

Tomemos como ejemplo una representación de empresas de descanso. En este ejemplo hipotético, cada compañía posee 0 o más departamentos y cada departamento posee 0 o más empleados.

Un departamento no puede existir sin una empresa asociada.

Un empleado no puede existir sin un departamento asociado.

Ahora encontraría la representación natural de los patrones de recursos.

  • /companies Una colección de empresas - Acepta poner para una nueva empresa. Obtener por toda la colección.
  • /companies/{companyId} Una empresa individual. Acepta GET, PUT y DELETE
  • /companies/{companyId}/departments Acepta POST para un nuevo artículo. (Crea un departamento dentro de la empresa.)
  • /companies/{companyId}/departments/{departmentId}/
  • /companies/{companyId}/departments/{departmentId}/employees
  • /companies/{companyId}/departments/{departmentId}/employees/{empId}

Dadas las restricciones, en cada una de las secciones, siento que esto tiene sentido si está un poco profundamente anidado.

Sin embargo, mi dificultad viene si quiero enumerar ( GET ) a todos los empleados de todas las compañías.

El patrón de recursos para eso se asignaría más estrechamente a /employees (La recopilación de todos los empleados)

¿Eso significa que debo tener /employees/{empId} también porque si es así, hay dos URI de conseguir el mismo recurso?

O tal vez todo el esquema debería ser aplanado, pero eso significaría que los empleados son un objeto anidado de nivel superior.

En un nivel básico /employees/?company={companyId}&department={deptId} devuelve exactamente la misma vista de empleados como el patrón más profundamente anidado.

¿Cuál es la mejor práctica para los patrones de URL donde los recursos son propiedad de otros recursos pero deberían poder consultarse por separado?

ACTUALIZACIÓN: ver mi respuesta a continuación para ver lo que he hecho.


El aspecto de tus URL no tiene nada que ver con REST. Todo vale. En realidad es un "detalle de implementación". Así que al igual que cómo nombras tus variables. Todo lo que tienen que ser es único y duradero.

No pierda demasiado tiempo en esto, solo elija y apéguese a él / sea consistente. Por ejemplo, si va con jerarquías, entonces lo hace para todos sus recursos. Si va con parámetros de consulta, etc., como las convenciones de nomenclatura en su código.

Porque ? Por lo que sé, una API "RESTful" debe ser navegable (ya sabes ... "Hipermedia como el motor del estado de la aplicación"), por lo tanto, a un cliente API no le importa cómo son tus URL siempre y cuando sean válido (no hay SEO, no hay humanos que necesiten leer esas "urls amigables", excepto que pueden ser para depurar ...)

Lo agradable / comprensible que es una URL en una API REST solo es interesante para usted como desarrollador de API, no como cliente API, como lo sería el nombre de una variable en su código.

Lo más importante es que su cliente API sepa cómo interpretar su tipo de medio. Por ejemplo sabe que:

  • su tipo de medio tiene una propiedad de enlaces que enumera enlaces disponibles / relacionados.
  • Cada enlace se identifica mediante una relación (al igual que los navegadores saben que el enlace [rel = "hoja de estilo"] significa que es una hoja de estilo o rel = favico es un enlace a un favicon ...)
  • y sabe lo que significan esas relaciones ("compañías" significa una lista de compañías, "búsqueda" significa una url programada para hacer una búsqueda en una lista de recursos, "departamentos" significa departamentos del recurso actual)

A continuación se muestra un ejemplo de intercambio HTTP (los cuerpos están en yaml ya que es más fácil de escribir):

Solicitud

GET / HTTP/1.1 Host: api.acme.io Accept: text/yaml, text/acme-mediatype+yaml

Respuesta: una lista de enlaces al recurso principal (empresas, personas, lo que sea ...)

HTTP/1.1 200 OK Date: Tue, 05 Apr 2016 15:04:00 GMT Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT Content-Type: text/acme-mediatype+yaml # body: this is your API''s entrypoint (like a homepage) links: # could be some random path https://api.acme.local/modskmklmkdsml # the only thing the API client cares about is the key (or rel) "companies" companies: https://api.acme.local/companies people: https://api.acme.local/people

Solicitud: enlace a empresas (utilizando body.links.companies de respuestas anteriores)

GET /companies HTTP/1.1 Host: api.acme.local Accept: text/yaml, text/acme-mediatype+yaml

Respuesta: una lista parcial de compañías (en los ítems), el recurso contiene enlaces relacionados, como el enlace para obtener las siguientes empresas (body.links.next) y otro enlace (con plantilla) para buscar (body.links.search)

HTTP/1.1 200 OK Date: Tue, 05 Apr 2016 15:06:00 GMT Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT Content-Type: text/acme-mediatype+yaml # body: representation of a list of companies links: # link to the next page next: https://api.acme.local/companies?page=2 # templated link for search search: https://api.acme.local/companies?query={query} # you could provide available actions related to this resource actions: add: href: https://api.acme.local/companies method: POST items: - name: company1 links: self: https://api.acme.local/companies/8er13eo # and here is the link to departments # again the client only cares about the key department department: https://api.acme.local/companies/8er13eo/departments - name: company2 links: self: https://api.acme.local/companies/9r13d4l # or could be in some other location ! department: https://api2.acme.local/departments?company=8er13eo

Entonces, como verás si vas por los enlaces / relaciones, la forma en que estructuras la parte de la ruta de tus URL no tiene ningún valor para tu cliente API. Y si está comunicando la estructura de sus URL a su cliente como documentación, entonces no está haciendo REST (o al menos no el Nivel 3 según el " Modelo de madurez de Richardson ")


He leído todas las respuestas anteriores, pero parece que no tienen una estrategia común. Encontré un buen artículo sobre las mejores prácticas en Design API de Microsoft Documents . Creo que deberías referirte.

En sistemas más complejos, puede ser tentador proporcionar URI que permitan a un cliente navegar a través de varios niveles de relaciones, tales como /customers/1/orders/99/products. Sin embargo, este nivel de complejidad puede ser difícil de mantener y es inflexible si las relaciones entre los recursos cambian en el futuro. En su lugar, trate de mantener las URI relativamente simples . Una vez que una aplicación tiene una referencia a un recurso, debería ser posible utilizar esta referencia para encontrar elementos relacionados con ese recurso. La consulta anterior se puede reemplazar con el URI /customers/1/orders para encontrar todos los pedidos para el cliente 1, y luego /orders/99/products para encontrar los productos en este orden.

.

Propina

Evite requerir URI de recursos más complejos que la collection/item/collection .


He probado ambas estrategias de diseño: puntos finales anidados y no anidados. He encontrado que

  1. Si el recurso anidado tiene una clave principal y usted no tiene su clave primaria principal, la estructura anidada requiere que la obtenga, aunque el sistema no la requiera.

  2. Los puntos finales anidados normalmente requieren puntos finales redundantes. En otras palabras, usted más a menudo que no, necesitan los empleados adicionales / de punto final para que pueda obtener una lista de los empleados en todos los departamentos. Si tiene / empleados, ¿qué es exactamente lo que compran / empresas / departamentos / empleados?

  3. Los puntos finales de anidación no evolucionan tan bien. Por ejemplo, es posible que no necesite buscar empleados ahora, pero puede hacerlo más tarde y si tiene una estructura anidada, no tiene más remedio que agregar otro punto final. Con un diseño no anidado, solo agrega más parámetros, que es más simple.

  4. A veces un recurso puede tener múltiples tipos de padres. Resultando en múltiples puntos finales, todos devolviendo el mismo recurso.

  5. los puntos finales redundantes hacen que la documentación sea más difícil de escribir y también hace que la API sea más difícil de aprender.

En resumen, el diseño no anidado parece permitir un esquema de punto final más flexible y más simple.


He trasladado lo que he hecho de la pregunta a una respuesta donde es probable que más personas lo vean.

Lo que he hecho es tener los puntos finales de creación en el punto final anidado. El punto final canónico para modificar o consultar un elemento no está en el recurso anidado .

Entonces, en este ejemplo (solo listando los puntos finales que cambian un recurso)

  • POST /companies/ crea una nueva compañía devuelve un enlace a la compañía creada.
  • POST /companies/{companyId}/departments cuando se coloca un departamento crea el nuevo departamento devuelve un enlace a /departments/{departmentId}
  • PUT /departments/{departmentId} modifica un departamento
  • POST /departments/{deparmentId}/employees crea un nuevo empleado devuelve un enlace a /employees/{employeeId}

Así que hay recursos de nivel raíz para cada una de las colecciones. Sin embargo, la creación está en el objeto propietario .


Lo que has hecho es correcto. En general, puede haber muchos URI en el mismo recurso, no hay reglas que indiquen que no debería hacerlo.

Y, en general, es posible que necesite acceder a los elementos directamente o como un subconjunto de otra cosa, para que su estructura tenga sentido para mí.

Solo porque los empleados son accesibles bajo departamento:

company/{companyid}/department/{departmentid}/employees

No significa que no puedan ser accesibles bajo compañía también:

company/{companyid}/employees

Lo que devolvería empleados para esa empresa. Depende de lo que necesite su cliente consumidor, para eso debe diseñar.

Pero espero que todos los manipuladores de URLs utilizan el mismo código respaldo para satisfacer las peticiones de manera que no está duplicando código.


No estoy de acuerdo con este tipo de camino

GET /companies/{companyId}/departments

Si desea obtener departamentos, creo que es mejor usar un recurso de / department

GET /departments?companyId=123

Supongo que tiene una tabla de companies y una tabla de departments luego clases para mapearlas en el lenguaje de programación que usa. También asumo que los departamentos podrían asociarse a otras entidades que no sean empresas, por lo que un recurso / department es sencillo, es conveniente tener recursos asignados a tablas y tampoco necesita tantos puntos finales ya que puede reutilizarlos

GET /departments?companyId=123

para cualquier tipo de búsqueda, por ejemplo

GET /departments?name=xxx GET /departments?companyId=123&name=xxx etc.

Si quieres crear un departamento, el

POST /departments

se debe utilizar el recurso y el cuerpo de la solicitud debe contener el ID de la empresa (si el departamento puede estar vinculado a una sola compañía).