Primo
Secondo RFC 3986 §3.4 (Identificatori di risorse uniformi § (Componenti di sintassi) | Query
3.4 Query
Il componente di query contiene dati non gerarchici che, insieme ai dati nel componente di percorso (Sezione 3.3), servono a identificare una risorsa nell'ambito dello schema dell'URI e dell'autorità di denominazione (se presente).
I componenti di query servono per il recupero di dati non gerarchici; ci sono poche cose più gerarchiche in natura di un albero genealogico! Ergo - indipendentemente dal fatto che si pensi che sia "REST-y" o no- per conformarsi ai formati, protocolli e framework di e per lo sviluppo di sistemi su Internet, non è necessario utilizzare la stringa di query per identificare queste informazioni.
REST non ha nulla a che fare con questa definizione.
Prima di rispondere a domande specifiche, il parametro della query di "ricerca" è scarsamente denominato. Meglio sarebbe trattare il tuo segmento di query come un dizionario di coppie chiave-valore.
La stringa di query potrebbe essere definita in modo più appropriato come
?first_name={firstName}&last_name={lastName}&birth_date={birthDate}
eccetera.
Per rispondere alle tue domande specifiche
1) Quale design API è più RESTful e perché? Semanticamente, significano e si comportano allo stesso modo. L'ultima risorsa nell'URI è "figli", il che implica effettivamente che il client sta operando sulla risorsa figlio.
Non penso che sia così chiaro come sembra credere.
Nessuna di queste interfacce di risorse è RESTful. Il presupposto principale per lo stile architettonico RESTful è che le transizioni dello stato dell'applicazione devono essere comunicate dal server come hypermedia. Le persone hanno lavorato sulla struttura degli URI per renderli in qualche modo "URI RESTful", ma la letteratura formale relativa al REST in realtà ha ben poco da dire al riguardo. La mia opinione personale è che gran parte della meta-disinformazione su REST è stata pubblicata con l'intento di rompere vecchie, cattive abitudini. (Costruire un sistema veramente "RESTful" è in realtà un bel po 'di lavoro. L'industria è passata a "REST" e ha riempito alcune preoccupazioni ortogonali con qualifiche e restrizioni insensate.)
Ciò che la letteratura REST dice è che se si intende utilizzare HTTP come protocollo dell'applicazione, è necessario rispettare i requisiti formali delle specifiche del protocollo e non è possibile "inventare http mentre si procede e dichiarare comunque che si sta utilizzando http" ; se si intende utilizzare gli URI per identificare le risorse, è necessario rispettare i requisiti formali delle specifiche relative a URI / URL.
La tua domanda è indirizzata direttamente da RFC3986 §3.4, che ho collegato sopra. La linea di fondo su questo argomento è che anche se un URI conforme non è sufficiente per considerare un API "riposante", se si desidera che il sistema in realtà essere "RESTful" e si utilizza HTTP e URI, quindi non è possibile identificare i dati gerarchici attraverso la stringa di query perché:
3.4 Query
Il componente di query contiene dati non gerarchici
...E 'così semplice.
2) Quali sono i pro e i contro di ciascuno in termini di comprensibilità dal punto di vista del cliente e manutenibilità dal punto di vista del progettista.
I "pro" dei primi due sono che sono sulla buona strada . Il "contro" del terzo è che sembra essere completamente sbagliato.
Per quanto riguarda la comprensibilità e la manutenibilità, questi sono decisamente soggettivi e dipendono dal livello di comprensione dello sviluppatore del cliente e dalle costanti progettuali del progettista. La specifica URI è la risposta definitiva su come si suppone che gli URI debbano essere formattati. I dati gerarchici dovrebbero essere rappresentati nel percorso e con i parametri del percorso. I dati non gerarchici dovrebbero essere rappresentati nella query. Il frammento è più complicato, poiché la sua semantica dipende specificamente dal tipo di supporto della rappresentazione richiesta. Quindi, per affrontare la componente "comprensibilità" della tua domanda, cercherò di tradurre esattamente ciò che i tuoi primi due URI stanno effettivamente dicendo. Quindi, tenterò di rappresentare ciò che dici che stai cercando di realizzare con URI validi.
Traduzione dei tuoi URI verbali al loro significato semantico
/myservice/api/v1/grandparents/{grandparentID}/parents/children?search={text}
Questo dice per i genitori dei nonni, trova il loro bambino avere search={text}
quello che hai detto con il tuo URI è coerente solo se cerca i fratelli di un nonno. Con i tuoi "nonni, genitori, figli" hai scoperto che un "nonno" è cresciuto di generazione in generazione dai loro genitori e poi è tornato alla generazione di "nonni" guardando i figli dei genitori.
/myservice/api/v1/parents/{parentID}/children?search={text}
Questo dice che per il genitore identificato da {parentID}, trova il figlio che ha ?search={text}
Questo è più vicino alla correzione di ciò che desideri e rappresenta una relazione genitore-> figlio che può essere probabilmente usata per modellare l'intera API. Per modellarlo in questo modo, l'onere è a carico del cliente per riconoscere che se hanno un "grandparentId", esiste un livello di riferimento indiretto tra l'ID che hanno e la parte del grafico familiare che desiderano vedere. Per trovare un "bambino" in "grandparentId", puoi chiamare il tuo /parents/{parentID}/children
servizio e quindi cercare un figlio che viene restituito, cerca i loro figli per l'identificatore della persona.
Implementazione dei tuoi requisiti come URI
Se vuoi modellare un identificatore di risorse più estensibile che possa camminare sull'albero, posso pensare a diversi modi in cui puoi farlo.
1) Il primo a cui ho già accennato. Rappresenta il grafico di "Persone" come una struttura composita. Ogni persona ha un riferimento alla generazione sopra di essa attraverso il suo percorso dei genitori e a una generazione sotto di essa attraverso il suo percorso dei figli.
/Persons/Joe/Parents/Mother/Parents
sarebbe un modo per prendere i nonni materni di Joe.
/Persons/Joe/Parents/Parents
sarebbe un modo per prendere tutti i nonni di Joe.
/Persons/Joe/Parents/Parents?id={Joe.GrandparentID}
afferrerebbe il nonno di Joe con l'identificatore che hai in mano.
e tutti questi avrebbero senso (notare che qui potrebbe esserci una penalità per le prestazioni in base all'attività forzando un dfs sul server a causa della mancanza di identificazione del ramo nel modello "Genitori / Genitori / Genitori"). la capacità di supportare qualsiasi numero arbitrario di generazioni. Se, per qualche motivo, desideri cercare 8 generazioni, potresti rappresentarlo come
/Persons/Joe/Parents/Parents/Parents/Parents/Parents/Parents/Parents/Parents?id={Joe.NotableAncestor}
ma questo porta alla seconda opzione dominante per rappresentare questi dati: attraverso un parametro path.
2) Usa i parametri del percorso per "interrogare la gerarchia". Potresti sviluppare la seguente struttura per aiutare ad alleviare l'onere per i consumatori e avere ancora un'API che abbia senso.
Per guardare indietro di 147 generazioni, rappresentando questo identificatore di risorsa con i parametri del percorso è possibile farlo
/Persons/Joe/Parents;generations=147?id={Joe.NotableAncestor}
Per localizzare Joe dal suo bisnonno, puoi guardare nel grafico un numero noto di generazioni per l'ID di Joe.
/Persons/JoesGreatGrandparent/Children;generations=3?id={Joe.Id}
La cosa più importante di questi approcci è che senza ulteriori informazioni nell'identificatore e nella richiesta, dovresti aspettarti che il primo URI stia recuperando una persona di 147 generazioni da Joe con l'identificatore di Joe.NotableAncestor. Dovresti aspettarti che il secondo recuperi Joe. Supponiamo che ciò che desideri effettivamente sia che il tuo client chiamante sia in grado di recuperare l'intero set di nodi e le loro relazioni tra la persona root e il contesto finale del tuo URI. È possibile farlo con lo stesso URI (con qualche decorazione aggiuntiva) e impostando Accetta text/vnd.graphviz
sulla richiesta, che è il tipo di supporto registrato IANA per la .dot
rappresentazione grafica. Con ciò, cambia l'URI in
/Persons/Joe/Parents;generations=147?id={Joe.NotableAncestor.Id}#directed
con un'intestazione di richiesta HTTP
Accept: text/vnd.graphviz
e puoi avere i clienti che comunicano abbastanza chiaramente che vogliono il grafico diretto della gerarchia generazionale tra Joe e 147 generazioni precedenti, dove quella 147a generazione ancestrale contiene una persona identificata come "Notable Ancestor" di Joe.
Non sono sicuro che text / vnd.graphviz abbia semantiche predefinite per il suo frammento; non sono riuscito a trovarne nessuna in una ricerca di istruzioni. Se quel tipo di supporto contiene effettivamente informazioni predefinite sui frammenti, è necessario seguirne la semantica per creare un URI conforme. Tuttavia, se tali semantiche non sono predefinite, la specifica URI afferma che la semantica dell'identificatore di frammento non è vincolata e viene invece definita dal server, rendendo valido questo utilizzo.
3) A cosa servono realmente le stringhe di query, oltre al "filtro" sulla tua risorsa? Se si segue il primo approccio, il parametro filter viene incorporato nell'URI stesso come parametro path anziché come parametro della stringa di query.
Credo di averlo già completamente battuto a morte, ma le stringhe di query non servono per "filtrare" le risorse. Sono per identificare la tua risorsa da dati non gerarchici. Se hai approfondito la tua gerarchia con il tuo percorso andando
/person/{id}/children/
e desideri identificare un figlio specifico o un insieme specifico di figli, utilizzeresti alcuni attributi che si applicano all'insieme che stai identificando e lo includeresti all'interno della query.