api - una - verbos http rest
¿Cómo debo tratar las jerarquías de objetos en una API RESTful? (4)
Actualmente estoy diseñando la API para una aplicación PHP existente, y para este fin estoy investigando REST como un enfoque arquitectónico sensato.
Creo que tengo una comprensión razonable de los conceptos clave, pero estoy luchando por encontrar a alguien que haya abordado las jerarquías de objetos y REST.
Aquí está el problema ...
En la jerarquía de objetos comerciales [aplicación] tenemos:
Users
L which have one-to-many Channel objects
L which have one-to-many Member objects
En la propia aplicación, utilizamos un enfoque de carga diferida para rellenar el objeto Usuario con matrices de estos objetos según sea necesario. Creo que en términos OO esto es agregación de objetos, pero he visto varias incoherencias en los nombres y no me importa comenzar una guerra sobre la convención de nomenclatura precisa.
Por ahora, considere que tengo algunos objetos débilmente acoplados que puedo / no puedo poblar dependiendo de la necesidad de la aplicación.
Desde una perspectiva de REST, estoy tratando de determinar cuál debería ser el enfoque. Aquí está mi pensamiento actual (considerando GET solo por el momento):
Opción 1: llena completamente los objetos:
GET api.example.com/user/{user_id}
Lea el objeto Usuario (recurso) y devuelva el objeto Usuario con todos los objetos Channel y Member posibles precargados y codificados (JSON o XML).
PROS: reduce el número de objetos, no se requiere el cruce de jerarquías de objeto
CONTRAS: los objetos deben estar completamente poblados (costosos)
Opción 2: complete el objeto primario e incluya enlaces a los otros recursos del objeto:
GET api.example.com/user/{user_id}
Lea el objeto Usuario (recurso) y devuelva el objeto Usuario Datos de usuario poblados y dos listas.
Cada lista hace referencia al (sub) recurso apropiado, es decir,
api.example.com/channel/{channel_id}
api.example.com/member/{member_id}
Creo que esto está cerca (o exactamente) de las implicaciones de los hipermedios: el cliente puede obtener los otros recursos si lo desea (siempre y cuando los etiquete con sensatez).
PROS: el cliente puede elegir cargar los subordinados o de otra manera, una mejor separación de los objetos como recursos REST
CONTRAS: se requiere más viaje para obtener los recursos secundarios
Opción 3: habilitar recuperaciones recursivas
GET api.example.com/user/{user_id}
Lea el objeto Usuario e incluya enlaces a listas de los subobjetos, es decir,
api.example.com/user/{user_id}/channels
api.example.com/user/{user_id}/members
la llamada / channels devolverá una lista de recursos de canal en el formulario (como se indicó anteriormente):
api.example.com/channel/{channel_id}
PROS: los recursos principales exponen dónde ir para obtener los subodintos pero no lo que son (¿más RESTful?), No es necesario obtener los subordinados por adelantado, los generadores de listas subordinadas (/ channels y / members) proporcionan interfaces (métodos como) la respuesta más servicio como.
CONTRAS: ahora se requieren tres llamadas para completar completamente el objeto
Opción 4 - (re) considerar el diseño del objeto para REST
Estoy reutilizando la jerarquía de objetos de aplicación [existente] e intentando aplicarla a REST, o tal vez de manera más directa, le proporcione una interfaz de API.
Quizás la jerarquía de objetos REST sea diferente, o tal vez el nuevo pensamiento RESTful expone las limitaciones del diseño de objetos existente.
Cualquier idea sobre lo anterior es bienvenida.
Muchas gracias
Pablo
Aquí están mis conclusiones de muchas horas buscando y con la opinión de los que respondieron aquí:
Cuando tengo un objeto que es efectivamente un objeto de varias partes, necesito tratarlo como un único recurso. Por lo tanto, si OBTENGO el objeto, todas las coordenadas deberían estar presentes. Esto es necesario para que el recurso sea almacenable en caché. Si cargo parcialmente el objeto (y proporciono un sello ETag), entonces otros solicitantes pueden recibir un objeto parcial cuando esperan uno completo. Concluya: los objetos deben estar completamente poblados si están disponibles como recursos.
Las relaciones de objeto asociadas deberían estar disponibles como enlaces a otros recursos (primarios). De esta forma, los objetos son detectables al atravesar la API.
Además, la jerarquía de objetos que tiene sentido para el sitio principal de la aplicación puede parecer que no es lo que necesita para actuar de manera RESTful, pero es más probable que revele problemas con la jerarquía existente. Habiendo dicho esto, la API puede requerir casos de uso más especializados de lo que se había previsto anteriormente, y es posible que se requieran recursos especializados.
Espero que ayude a alguien
El mejor consejo que puedo dar es tratar de evitar pensar en su API REST como la exposición de sus objetos. Los recursos que cree deben respaldar los casos de uso que necesite. Si es necesario, puede crear recursos para las tres opciones:
api.example.com/completeuser/{id}
api.example.com/linkeduser/{id}
api.example.com/lightweightuser/{id}
Obviamente mis nombres son un poco tontos, pero realmente no importa cómo los llames. La idea es usar la API REST para presentar datos de la manera más lógica para el escenario de uso particular. Si hay múltiples escenarios, cree múltiples recursos, si es necesario. Me gusta pensar que mis recursos se parecen más a los modelos de IU que a las entidades comerciales.
No hay razón para no combinar estos.
-
api.example.com/user/{user_id}
- devuelve una representación de usuario -
api.example.com/channel/{channel_id}
- devuelve una representación de canal -
api.example.com/user/{user_id}/channels
- devuelve una lista de representaciones de canales -
api.example.com/user/{user_id}/channel_list
- devuelve una lista de identificadores de canal (o enlaces a sus representaciones completas, utilizando los enlaces anteriores)
En caso de duda, piense en cómo mostraría los datos a un usuario humano sin preocupaciones de "API": un usuario desea tanto páginas de índice ( {user_id}/channel_list
) como vistas completas ( {user_id}/channels
).
Una vez que tenga eso, solo soporte JSON en lugar de (o además de) HTML como el formato de representación, y tiene REST.
Recomendaría Restful Obects, que son estándares para exponer el modelo de dominio de descanso
La idea de Restful Objects es proporcionar una interfaz estándar RESTful genérica para modelos de objetos de dominio, exponiendo representaciones de su estructura mediante JSON y habilitando las interacciones con instancias de objetos de dominio utilizando HTTP GET, POST, PUT y DELETE.
De acuerdo con el estándar, los URI serán como:
- api.example.com/object/user/31
- api.example.com/object/user/31/properties/username
- api.example.com/object/user/31/collections/channels
- api.example.com/object/user/31/collections/members
- api.example.com/object/user/31/actions/someFunction
- api.example.com/object/user/31/actions/someFunction/invoke
También hay otros recursos
- api.example.com/services
- api.example.com/domain-types
La especificación define algunas representaciones primarias:
- objeto (que representa cualquier objeto o servicio de dominio)
- lista (de enlaces a otros objetos)
- propiedad
- colección
- acción
- resultado de acción (que normalmente contiene un objeto o una lista, o simplemente mensajes de retroalimentación)
- y también un pequeño número de representaciones secundarias como el hogar y el usuario
Esto es interesante ya que verá que las representaciones son totalmente autodescriptivas, lo que abre la posibilidad de que los usuarios genéricos se implementen si es necesario.
Alternativamente, las representaciones pueden ser consumidas directamente por una aplicación a medida.