primero
Según RFC 3986 §3.4 (Identificadores uniformes de recursos § (Componentes de sintaxis) | Consulta
3.4 Consulta
El componente de consulta contiene datos no jerárquicos que, junto con los datos en el componente de ruta (Sección 3.3), sirven para identificar un recurso dentro del alcance del esquema y la autoridad de denominación del URI (si corresponde).
Los componentes de consulta son para recuperar datos no jerárquicos; ¡Hay pocas cosas más jerárquicas en la naturaleza que un árbol genealógico! Ergo , independientemente de si cree que es "REST-y" o no , para cumplir con los formatos, protocolos y marcos de trabajo y para desarrollar sistemas en Internet, no debe usar la cadena de consulta para identificar esta información.
REST no tiene nada que ver con esta definición.
Antes de abordar sus preguntas específicas, su parámetro de consulta de "búsqueda" está mal nombrado. Mejor sería tratar su segmento de consulta como un diccionario de pares clave-valor.
Su cadena de consulta podría definirse más apropiadamente como
?first_name={firstName}&last_name={lastName}&birth_date={birthDate}
etc.
Para responder a sus preguntas específicas
1) ¿Qué diseño de API es más RESTful y por qué? Semánticamente, significan y se comportan de la misma manera. El último recurso en el URI es "hijos", lo que implica efectivamente que el cliente está operando en el recurso hijos.
No creo que esto sea tan claro como parece creer.
Ninguna de estas interfaces de recursos es RESTful. La condición previa principal para el estilo arquitectónico RESTful es que las transiciones de estado de la aplicación deben comunicarse desde el servidor como hipermedia. La gente ha trabajado sobre la estructura de los URI para hacerlos de alguna manera "URI RESTful", pero la literatura formal sobre REST en realidad tiene muy poco que decir al respecto. Mi opinión personal es que gran parte de la metainformación errónea sobre REST se publicó con la intención de romper viejos y malos hábitos. (Construir un sistema verdaderamente "RESTful" es en realidad bastante trabajo. La industria recurrió a "REST" y rellenó algunas preocupaciones ortogonales con calificaciones y restricciones sin sentido).
Lo que dice la literatura REST es que si va a utilizar HTTP como su protocolo de aplicación, debe cumplir con los requisitos formales de las especificaciones del protocolo y no puede "inventar http sobre la marcha y aún declarar que está utilizando http" ; Si va a utilizar URI para identificar sus recursos, debe cumplir con los requisitos formales de las especificaciones sobre URI / URL.
Su pregunta es abordada directamente por RFC3986 §3.4, que he vinculado anteriormente. La conclusión sobre este asunto es que, aunque un URI conforme sea insuficiente para considerar una API "RESTful", si desea que su sistema sea realmente "RESTful" y esté utilizando HTTP y URI, no podrá identificar datos jerárquicos a través de cadena de consulta porque:
3.4 Consulta
El componente de consulta contiene datos no jerárquicos.
...Es tan simple como eso.
2) ¿Cuáles son los pros y los contras de cada uno en términos de comprensibilidad desde la perspectiva del cliente y mantenibilidad desde la perspectiva del diseñador?
Los "pros" de los dos primeros es que están en el camino correcto . La "desventaja" del tercero es que parece estar completamente equivocado.
En lo que respecta a sus problemas de comprensibilidad y mantenibilidad, estos son definitivamente subjetivos y dependen del nivel de comprensión del desarrollador del cliente y de las habilidades de diseño del diseñador. La especificación de URI es la respuesta definitiva en cuanto a cómo se supone que deben formatearse los URI. Se supone que los datos jerárquicos se representan en la ruta y con los parámetros de la ruta. Se supone que los datos no jerárquicos se representan en la consulta. El fragmento es más complicado, porque su semántica depende específicamente del tipo de medios de la representación que se solicita. Por lo tanto, para abordar el componente de "comprensibilidad" de su pregunta, intentaré traducir exactamente lo que en realidad están diciendo sus dos primeros URI. Luego, intentaré representar lo que dices que estás tratando de lograr con URI válidos.
Traducción de sus URI literales a su significado semántico
/myservice/api/v1/grandparents/{grandparentID}/parents/children?search={text}
Esto dice para los padres de los abuelos, encontrar a su hijo teniendo search={text}
Lo que usted dijo con su URI solo es coherente si busca a los hermanos de un abuelo. Con tus "abuelos, padres, hijos" encontraste que un "abuelo" subía una generación a sus padres y luego volvía a la generación de "abuelos" mirando a los hijos de los padres.
/myservice/api/v1/parents/{parentID}/children?search={text}
Esto dice que para el padre identificado por {parentID}, encuentre que su hijo tiene ?search={text}
Esto está más cerca de corregir lo que desea y representa una relación padre-> hijo que probablemente se pueda usar para modelar toda su API. Para modelarlo de esta manera, el cliente tiene la responsabilidad de reconocer que si tienen un "grandparentId", existe una capa de indirección entre la ID que tienen y la parte del gráfico familiar que desean ver. Para encontrar un "niño" por "grandparentId", puede llamar a su /parents/{parentID}/children
servicio y luego, para cada niño que se devuelva, busque su identificador de persona en sus niños.
Implementación de sus requisitos como URI
Si desea modelar un identificador de recursos más extensible que pueda recorrer el árbol, puedo pensar en varias formas en que puede lograrlo.
1) El primero, al que ya he aludido. Representar el gráfico de "Personas" como una estructura compuesta. Cada persona tiene una referencia a la generación superior a través de su ruta de Padres y a una generación inferior a través de su ruta de Hijos.
/Persons/Joe/Parents/Mother/Parents
sería una forma de agarrar a los abuelos maternos de Joe.
/Persons/Joe/Parents/Parents
sería una forma de agarrar a todos los abuelos de Joe.
/Persons/Joe/Parents/Parents?id={Joe.GrandparentID}
agarraría al abuelo de Joe con el identificador que tiene en la mano.
y todo esto tendría sentido (tenga en cuenta que podría haber una penalización de rendimiento aquí dependiendo de la tarea al forzar un dfs en el servidor debido a la falta de identificación de sucursal en el patrón "Padres / Padres / Padres"). También se beneficia de tener la capacidad de soportar cualquier número arbitrario de generaciones. Si, por alguna razón, desea buscar 8 generaciones, podría representar esto como
/Persons/Joe/Parents/Parents/Parents/Parents/Parents/Parents/Parents/Parents?id={Joe.NotableAncestor}
pero esto lleva a la segunda opción dominante para representar estos datos: a través de un parámetro de ruta.
2) Use parámetros de ruta para "consultar la jerarquía". Podría desarrollar la siguiente estructura para ayudar a aliviar la carga de los consumidores y aún así tener una API que tenga sentido.
Para mirar hacia atrás 147 generaciones, representar este identificador de recursos con parámetros de ruta le permite hacer
/Persons/Joe/Parents;generations=147?id={Joe.NotableAncestor}
Para localizar a Joe de su bisabuelo, puede mirar hacia abajo en el gráfico un número conocido de generaciones para Joe's Id.
/Persons/JoesGreatGrandparent/Children;generations=3?id={Joe.Id}
Lo más importante con estos enfoques es que sin más información en el identificador y la solicitud, debe esperar que el primer URI esté recuperando una Persona 147 generaciones de Joe con el identificador de Joe.NotableAncestor. Deberías esperar que el segundo recupere a Joe. Suponga que lo que realmente desea es que su cliente llamante pueda recuperar todo el conjunto de nodos y sus relaciones entre la Persona raíz y el contexto final de su URI. Puede hacerlo con el mismo URI (con algo de decoración adicional) y establecer un Aceptar text/vnd.graphviz
en su solicitud, que es el tipo de medio registrado de IANA para la .dot
representación gráfica. Con eso, cambie el URI a
/Persons/Joe/Parents;generations=147?id={Joe.NotableAncestor.Id}#directed
con un encabezado de solicitud HTTP
Accept: text/vnd.graphviz
y puede hacer que los clientes comuniquen con bastante claridad que desean el gráfico dirigido de la jerarquía generacional entre Joe y 147 generaciones anteriores, donde esa 147a generación ancestral contiene una persona identificada como el "Ancestro notable" de Joe.
No estoy seguro de si text / vnd.graphviz tiene alguna semántica predefinida para su fragmento; no pude encontrar ninguna en la búsqueda de instrucciones. Si ese tipo de medio realmente tiene información de fragmento predefinida, entonces se debe seguir su semántica para crear un URI conforme. Pero, si esa semántica no está predefinida, la especificación de URI establece que la semántica del identificador de fragmento no está restringida y, en su lugar, el servidor la define, lo que hace que este uso sea válido.
3) ¿Para qué se utilizan realmente las cadenas de consulta, además de "filtrar" en su recurso? Si opta por el primer enfoque, el parámetro de filtro se incrusta en el URI como un parámetro de ruta en lugar de un parámetro de cadena de consulta.
Creo que ya lo he derrotado completamente, pero las cadenas de consulta no son para "filtrar" recursos. Son para identificar su recurso a partir de datos no jerárquicos. Si ha perforado abajo de su jerarquía con su camino yendo
/person/{id}/children/
y que está deseando para identificar un determinado niño o un determinado conjunto de los niños, se utilizaría algún atributo que se aplica al conjunto que está identificando e incluirla dentro de la consulta.