Quando uso i parametri del percorso rispetto ai parametri della query in un'API RESTful?


141

Voglio rendere la mia API RESTful molto prevedibile. Qual è la migliore pratica per decidere quando effettuare una segmentazione dei dati utilizzando l'URI anziché utilizzando i parametri di query.

Per me ha senso che i parametri di sistema che supportano l'impaginazione, l'ordinamento e il raggruppamento siano dopo il '?' Ma che dire di campi come "stato" e "regione" o altri attributi che segmentano la tua collezione? Se anche quelli devono essere parametri di query, qual è la regola empirica per sapere quando usare i parametri di percorso?


1
una domanda simile viene data qui ... stackoverflow.com/questions/3198492/…
Lalit Mehra

Risposte:


239

La migliore pratica per la progettazione dell'API RESTful è che i parametri del percorso vengono utilizzati per identificare una o più risorse specifiche, mentre i parametri della query vengono utilizzati per ordinare / filtrare tali risorse.

Ecco un esempio Supponiamo di implementare endpoint API RESTful per un'entità chiamata Car. Dovresti strutturare i tuoi endpoint in questo modo:

GET /cars
GET /cars/:id
POST /cars
PUT /cars/:id
DELETE/cars/:id

In questo modo si utilizzano i parametri del percorso solo quando si specifica quale risorsa recuperare, ma ciò non ordina / filtra le risorse in alcun modo.

Supponiamo ora che tu voglia aggiungere la possibilità di filtrare le auto per colore nelle tue richieste GET. Poiché il colore non è una risorsa (è una proprietà di una risorsa), è possibile aggiungere un parametro di query che lo faccia. Aggiungeresti quel parametro di query alla tua richiesta GET in/cars questo modo:

OTTENERE /cars?color=blue

Questo endpoint verrebbe implementato in modo da restituire solo le auto blu.

Per quanto riguarda la sintassi, i nomi dei tuoi URL dovrebbero essere tutti in minuscolo. Se hai un nome di entità che in genere è di due parole in inglese, useresti un trattino per separare le parole, non il caso di cammello.

Ex. /two-words


3
Grazie per la tua risposta Mike. Questa è una metodologia chiara e semplice; merita un voto positivo da parte mia. Tuttavia, spesso gli sviluppatori optano per l'approccio "auto / blu", mi chiedo quale sia il loro ragionamento per farlo ... forse decidono di fare parametri di percorso per i campi obbligatori, o forse lo fanno per indicare che il database è partizionato da quel frammento.
cosbor11

1
Non sono sicuro di quale sia il loro ragionamento. Onestamente, non sono d'accordo. Penso che seguire le convenzioni e mantenerlo semplice abbia più senso. In questo modo, consenti agli utenti della tua API di comprendere meglio cosa devono fare per accedere alla sua funzionalità.
Mike,

3
che dire di / automobili? id = 1 e colore = blu anziché automobili / 1 /? colore = blu. fondamentalmente stai filtrando le risorse delle auto in ogni scenario
mko

1
Sbagliato poiché un'auto con ID 1 ne esiste solo una, ma le auto con il colore blu forse sono molte. C'è una distinzione tra identità e filtro
paul

1
La mia ipotesi sul perché l'uso di path params sia così diffusa è perché molti sviluppatori hanno imparato dai framework progettati da persone che non avevano una buona conoscenza dei principi REST (Ruby on Rails in particolare.)
Chris Broski,

58

Il modo fondamentale di pensare a questo argomento è il seguente:

Un URI è un identificatore di risorsa che identifica in modo univoco un'istanza specifica di un TIPO di risorsa. Come ogni altra cosa nella vita, ogni oggetto (che è un'istanza di qualche tipo), ha un insieme di attributi che sono invarianti nel tempo o temporali.

Nell'esempio sopra, un'auto è un oggetto molto tangibile che ha attributi come marca, modello e VIN - che non cambia mai, e colore, sospensioni ecc. Che possono cambiare nel tempo. Quindi se codifichiamo l'URI con attributi che possono cambiare nel tempo (temporali), potremmo finire con URI multipli per lo stesso oggetto:

GET /cars/honda/civic/coupe/{vin}/{color=red}

E anni dopo, se il colore di questa stessa macchina viene cambiato in nero:

GET /cars/honda/civic/coupe/{vin}/{color=black}

Nota che l'istanza dell'auto stessa (l'oggetto) non è cambiata - è solo il colore che è cambiato. Avere più URI che puntano alla stessa istanza di oggetto ti costringerà a creare più gestori URI: questa non è una progettazione efficiente e ovviamente non è intuitiva.

Pertanto, l'URI dovrebbe essere costituito solo da parti che non cambieranno mai e continuerà a identificare in modo univoco quella risorsa per tutta la sua vita. Tutto ciò che può cambiare dovrebbe essere riservato ai parametri della query, in quanto tale:

GET /cars/honda/civic/coupe/{vin}?color={black}

In conclusione: pensa al polimorfismo.


2
Interessante paradigma .. È un patten di design comunemente usato? Puoi fornire alcune API che lo utilizzano nella loro documentazione o alcuni riferimenti che delineano questa strategia?
cosbor11

1
Mi piace come hai enfatizzato "TYPE" quando hai scritto "Un URI è un identificatore di risorse che identifica in modo univoco un'istanza specifica di un tipo di risorsa". Penso che sia una distinzione importante.
jrahhali,

15

In un'API REST, non dovresti essere eccessivamente preoccupato per gli URI prevedibili. Il suggerimento stesso della prevedibilità dell'URI allude a un fraintendimento dell'architettura RESTful. Presuppone che un client dovrebbe costruire gli URI stessi, cosa che in realtà non dovrebbero.

Tuttavia, suppongo che tu non stia creando una vera API REST, ma un'API "ispirata a REST" (come quella di Google Drive). In questi casi, la regola empirica è "path params = identificazione delle risorse" e "query params = ordinamento delle risorse". Quindi, la domanda diventa: puoi identificare in modo univoco la tua risorsa SENZA stato / regione? Se sì, allora forse è un parametro di query. Se no, allora è un parametro param.

HTH.


11
Non sono d'accordo, una buona API dovrebbe essere prevedibile; RESTful o altro.
cosbor11

3
Credo di si. Dovrebbero esserci rima e ragione su come si forma l'URI, piuttosto che nominare arbitrariamente gli endpoint. Quando uno può intuitivamente scrivere un client API senza fare costantemente riferimento alla documentazione, a mio avviso hai scritto una buona API.
cosbor11

2
"Quando si può scrivere intuitivamente un client API senza fare costantemente riferimento alla documentazione". È qui che penso che la nostra comprensione del REST differisca ... il client API non dovrebbe mai aver bisogno di "costruire" un URL. Dovrebbero selezionarlo dalla risposta della precedente chiamata API. Se consideri un sito Web come un'analogia ... Vai su facebook.com, quindi selezioni un collegamento alla pagina degli eventi. Non ti importa se l'URL degli eventi di Facebook è "prevedibile", mentre non lo digiti. Ci arrivi tramite collegamenti ipertestuali. Lo stesso vale per un'API REST. Quindi, rendi gli URI significativi per te (il server), ma non per il client
Oliver McPhee,

2
Nota aggiunta. Ciò non significa che gli URI non debbano seguire uno schema di facile comprensione, significa solo che non è un vincolo di un'API RESTful. Il problema più grande in quest'area sono le persone che presumono che un client debba creare gli URL stessi. Non dovrebbero, poiché ciò crea un accoppiamento tra client e server che non dovrebbe esistere. (ad es. il server non può quindi modificare un URL senza interrompere tutte le applicazioni client). In un'API REST, il server può modificarli a proprio piacimento.
Oliver McPhee,

3
+1 per l'utilizzo delle seguenti parole: "'path params = identificazione delle risorse' e 'query params = ordinamento delle risorse'". Questo mi ha chiarito davvero tutto.
Doug,

3

Una volta ho progettato un'API quale principale risorsa era people. Di solito gli utenti chiedevano di filtrare peoplecosì, per evitare che gli utenti chiamassero qualcosa come /people?settlement=urbanogni volta, ho implementato ciò /people/urbanche in seguito mi ha permesso di aggiungere facilmente /people/rural. Inoltre, questo consente di accedere /peopleall'elenco completo se sarebbe utile in seguito. In breve, il mio ragionamento era quello di aggiungere un percorso a sottoinsiemi comuni

Da qui :

Alias ​​per query comuni

Per rendere l'esperienza API più piacevole per il consumatore medio, prendere in considerazione la creazione di pacchetti di condizioni in percorsi RESTful facilmente accessibili. Ad esempio, la query di ticket chiusa di recente sopra potrebbe essere impacchettata comeGET /tickets/recently_closed


1

In generale, tendo a utilizzare i parametri del percorso quando esiste una "gerarchia" evidente nella risorsa, come ad esempio:

/region/state/42

Se quella singola risorsa ha uno stato, si potrebbe:

/region/state/42/status

Tuttavia, se 'area' non fa veramente parte della risorsa esposta, probabilmente appartiene come uno dei parametri della query - simile alla paginazione (come hai detto tu).


0

La segmentazione è più gerarchica e "carina" ma può essere limitante.

Ad esempio, se hai un URL con tre segmenti, ognuno passa parametri diversi per cercare un'auto tramite marca, modello e colore:

www.example.com/search/honda/civic/blue

Questo è un URL molto carino e più facilmente ricordabile dall'utente finale, ma ora il tuo tipo di bloccato con questa struttura. Diciamo che vuoi farlo in modo che nella ricerca l'utente possa cercare TUTTE le auto blu o TUTTE le Honda Civics? Un parametro di query risolve questo perché fornisce una coppia valore-chiave. Quindi potresti passare:

www.example.com/search?color=blue
www.example.com/search?make=civic

Ora hai un modo per fare riferimento al valore tramite la sua chiave: "color" o "make" nel tuo codice di query.

È possibile aggirare questo problema utilizzando eventualmente più segmenti per creare una sorta di struttura di valori chiave come:

www.example.com/search/make/honda/model/civic/color/blue

Spero che abbia un senso ..


-2

URL di esempio: /rest/{keyword}

Questo URL è un esempio per i parametri del percorso. Possiamo ottenere questi dati URL utilizzando @PathParam.

URL di esempio: /rest?keyword=java&limit=10

Questo URL è un esempio di parametri di query. Possiamo ottenere questi dati URL utilizzando @Queryparam.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.