Best practice per l'API REST: dove inserire i parametri? [chiuso]


348

Un'API REST può avere parametri in almeno due modi:

  1. Come parte del percorso URL (ovvero /api/resource/parametervalue )
  2. Come argomento query (es. /api/resource?parameter=value )

Qual è la migliore pratica qui? Ci sono delle linee guida generali su quando usare 1 e quando usare 2?

Esempio reale: Twitter utilizza i parametri di query per specificare gli intervalli. ( http://api.twitter.com/1/statuses/home_timeline.json?since_id=12345&max_id=54321)

Sarebbe considerato un progetto migliore inserire questi parametri nel percorso URL?

Risposte:


254

Se esistono buone pratiche documentate, non le ho ancora trovate. Tuttavia, ecco alcune linee guida che utilizzo per determinare dove inserire i parametri in un URL:

I parametri opzionali tendono ad essere più facili da inserire nella stringa di query.

Se si desidera restituire un errore 404 quando il valore del parametro non corrisponde a una risorsa esistente, si tende verso un parametro del segmento di percorso. ad es. /customer/232dove 232 non è un ID cliente valido.

Se tuttavia si desidera restituire un elenco vuoto, quando il parametro non viene trovato, suggerisco di utilizzare i parametri della stringa di query. per esempio/contacts?name=dave

Se un parametro influenza un'intera sottostruttura del tuo spazio URI, utilizza un segmento di percorso. ad esempio un parametro di lingua /en/document/foo.txt rispetto a/document/foo.txt?language=en

Preferisco che gli identificatori univoci si trovino in un segmento di percorso piuttosto che in un parametro di query.

Le regole ufficiali per gli URI si trovano in questa specifica RFC qui . C'è anche un'altra specifica RFC molto utile qui che definisce le regole per la parametrizzazione degli URI.


5
Gli URI delle regole ufficiali e il progetto di sepc sono stati davvero utili e interessanti! :-)
KajMagnus

1
Il test di errore 404 mi aiuta molto a evitare di inserire informazioni nel percorso che appartiene ai parametri della query, alle intestazioni o al corpo della richiesta. Grazie per averlo sottolineato!
Kevin Condon,

152

Risposta tardiva, ma aggiungerò alcune informazioni aggiuntive a ciò che è stato condiviso, vale a dire che ci sono diversi tipi di "parametri" a una richiesta e dovresti tenerne conto.

  1. Localizzatori - Ad esempio identificatori di risorse come ID o azione / vista
  2. Filtri: ad esempio parametri che consentono di cercare, ordinare o restringere il set di risultati.
  3. Stato: ad es. Identificazione della sessione, chiavi API, whatevs.
  4. Contenuto - Ad esempio i dati da archiviare.

Ora diamo un'occhiata ai diversi luoghi in cui questi parametri potrebbero andare.

  1. Richiedi intestazioni e cookie
  2. Stringa di query URL ("GET" vars)
  3. Percorsi URL
  4. Body query string / multipart ("POST" vars)

Generalmente si desidera che State sia impostato in intestazioni o cookie, a seconda del tipo di informazioni sullo stato. Penso che possiamo essere tutti d'accordo su questo. Utilizzare intestazioni http personalizzate (X-My-Header) se necessario.

Allo stesso modo, Contenuto ha solo un posto a cui appartenere, che si trova nel corpo della richiesta, come stringhe di query o come contenuto multipart http e / o JSON. Ciò è coerente con ciò che ricevi dal server quando ti invia contenuto. Quindi non dovresti essere scortese e farlo diversamente.

Localizzatori come "id = 5" o "action = refresh" o "page = 2" avrebbero senso avere come percorso URL, ad esempio mysite.com/article/5/page=2dove in parte sai cosa significa ogni parte (le basi come articolo e 5 ovviamente significa ottenere i dati dell'articolo di tipo con id 5) e parametri aggiuntivi sono specificati come parte dell'URI. Possono essere sotto forma di page=2, o page/2se si sa che dopo un certo punto nell'URI le "cartelle" sono valori-chiave associati.

I filtri vanno sempre nella stringa di query, perché mentre fanno parte della ricerca dei dati giusti, sono lì solo per restituire un sottoinsieme o la modifica di ciò che i Locatori restituiscono da soli. La ricerca in mysite.com/article/?query=Obama(sottoinsieme) è un filtro, così come /article/5?order=backwards(modifica). Pensa a cosa fa, non solo a come si chiama!

Se "view" determina il formato di output, allora è un filtro ( mysite.com/article/5?view=pdf) perché restituisce una modifica della risorsa trovata piuttosto che homing su quale risorsa vogliamo. Se invece decide quale parte specifica dell'articolo possiamo vedere ( mysite.com/article/5/view=summary), allora è un localizzatore.

Ricorda, restringere un insieme di risorse sta filtrando. Individuare qualcosa di specifico all'interno di una risorsa sta individuando ... duh. Il filtro del sottoinsieme può restituire un numero qualsiasi di risultati (anche 0). La ricerca troverà sempre quell'istanza specifica di qualcosa (se esiste). Il filtro di modifica restituirà gli stessi dati del localizzatore, tranne quelli modificati (se tale modifica è consentita).

Spero che questo abbia contribuito a dare alle persone dei momenti eureka se si sono persi su dove mettere le cose!


2
Perché idallora non è un filtro? Restituisce un sottoinsieme della risorsa
Jonathan.

13
@Jonathan. no restituisce una risorsa specifica, vale a dire l'articolo numero 5. Un filtro è sempre un modo per restringere una ricerca in una raccolta di risorse. Se vuoi solo quella specifica risorsa, allora dovrebbe esserci un modo designato per ottenerlo. Il filtro significa che hai la possibilità di restituire più risorse. Un ID non è un filtro, è una singola risorsa definita. Se avessi una GAMMA di ID, sarebbe un filtro, anche se l'intervallo includesse solo un ID. Se il filtro includesse anche tipi di risorse, restituirebbe tutte le risorse con ID 5, non solo l'articolo.
Tor Valamo,

1
@Jonathan .: come menzionato DarrelMiller, ti aspetteresti che una richiesta su oggetto / id restituisca 404 in caso di ID sconosciuto, mentre ti aspetteresti che oggetto? Id = id ritorni e svuoti la lista. Inoltre, considererei che qualsiasi tipo di filtro / sottoimpostazione dovrebbe restituire un elenco.
njzk2,

1
Le pagine sono difficili, perché come dici tu può essere un filtro di una risorsa (raccolta di pagine), ma allo stesso tempo è una risorsa specifica all'interno di quella raccolta. Vorrei sempre richiedere una pagina di articolo per localizzatore, non filtro. Tuttavia, la pagina può essere un filtro di un elenco di qualcosa, ad esempio un elenco di utenti. Ma poi la pagina è intrinsecamente un delimitatore, noto anche come "inizia dall'elemento (page-1)*perpagee mostra gli perpageelementi". Usarlo come filtro è corretto allora, ma per diversi motivi. Chiamarlo "pagina" è tecnicamente sbagliato. Più semanticamente corretto sarebbe chiamarlo "da" o "startAt"
Tor Valamo

1
(continua) Il significato semantico di "pagina" è che si tratta di una risorsa specifica che non cambia. Viene dalla stampa fisica. Se non avessimo mai avuto libri o materiale stampato, "pagina" non sarebbe davvero una parola. Se disponi di un elenco dinamico di elementi, suddiviso in "pagine", dovresti davvero fornire un punto di partenza specifico, numerico, alfabetico o persino specifico per l'elemento, nonché un filtro "quanti per pagina". Se voglio fare riferimento a qualcosa nella tua lista, voglio dei dettagli. Inoltre non voglio andare a pagina 5 solo per rendermi conto che ora hai cambiato l'interno perpagea 50 anziché a 20.
Tor Valamo

21

Dipende da un design. Non ci sono regole per gli URI su REST su HTTP (la cosa principale è che sono unici). Spesso si tratta della questione del gusto e dell'intuizione ...

Prendo il seguente approccio:

  • url path-element: la risorsa e il suo elemento path formano un attraversamento di directory e una sotto-risorsa (es. / items / {id}, / users / items). Se non sei sicuro chiedi ai tuoi colleghi, se pensano che attraversare e pensano in "un'altra directory" molto probabilmente l'elemento-percorso è la scelta giusta
  • parametro url: quando non c'è realmente un attraversamento (le risorse di ricerca con più parametri di query ne sono un ottimo esempio)

1
In realtà ci sono regole abbastanza chiare su come dovrebbe apparire un URI e pochissima ambiguità su come applicarli agli URI RESTful.
DanMan,

18

I parametri IMO dovrebbero essere migliori come argomenti di query. L'URL viene utilizzato per identificare la risorsa, mentre i parametri di query aggiunti per specificare quale parte della risorsa si desidera, qualsiasi stato dovrebbe avere la risorsa, ecc.


7
In realtà, sia il percorso che la query vengono utilizzati in combinazione per identificare la risorsa. Ciò è stato chiarito in RFC 3986 http://labs.apache.org/webarch/uri/rfc/rfc3986.html#query
Darrel Miller,

@DarrelMiller So che questo è un vecchio post, ma sono interessato a saperne di più sul fatto che i parametri della query vengono utilizzati anche per identificare la risorsa. Il link che hai fornito ora è morto. Ho esaminato RFC3986 ma non vedo come tu abbia dedotto questo fatto. Inoltre, per definizione, i parametri di un identificatore non dovrebbero essere facoltativi, quindi non sembra appropriato utilizzare i parametri della query per l'identificazione.
Mickael Marrache,

@MickaelMarrache Vedi la prima riga nella sezione 3.4 tools.ietf.org/html/rfc3986#section-3.4
Darrel Miller

2
@DarrelMiller Grazie! La mia domanda deriva dal fatto che generalmente i componenti HTTP intermedi non memorizzano nella cache le risposte alle richieste che contengono una stringa di query. Quindi, sembra che i parametri della query siano più appropriati per cercare risorse in base ad alcuni criteri e non per identificare in modo univoco una risorsa.
Mickael Marrache,

17

Secondo l'implementazione REST,

1) Le variabili del percorso vengono utilizzate per l'azione diretta sulle risorse, ad esempio un contatto o una canzone, ad esempio.
OTTIENI etc / api / resource / {songid} o
/ api / risorsa / {contactid} restituiranno i rispettivi dati.

2) I permessi / argomenti della query sono usati per le risorse dirette come i metadati di una canzone ad es., GET / api / resource / {songid}? Metadata = generi restituirà i dati relativi ai generi per quella particolare canzone.


5
In realtà non esiste uno standard REST . Per Wikipedia : a differenza dei servizi Web basati su SOAP, non esiste uno standard "ufficiale" per le API Web RESTful. [14] Questo perché REST è uno stile architettonico, a differenza di SOAP, che è un protocollo. Anche se REST non è uno standard, un'implementazione RESTful come il Web può utilizzare standard come HTTP, URI, XML, ecc.
DavidRR

Non mi piace l'approccio 2. Preferirei preferire / api / generi? Songid = 123 o / api / canzoni / {song-id} / generi
Bart Calixto,

1
@Bart, Satish si riferiva alle variabili nel percorso, che è essenzialmente quella a cui ti riferivi come la tua preferenza .. tuttavia, se i generi sono in realtà metadati e non un campo dell'entità / risorsa della canzone .. allora potrei vedere più sensibilità usando una stringa di query su di esso ..
Brett Caswell

@BrettCaswell capito! Grazie per segnalarlo. lo apprezzo davvero!
Bart Calixto,

16

"Raggruppa" e POST i tuoi dati contro il "contesto" fornito dall'universo-risorsa-localizzatore, che significa # 1 per il bene del localizzatore.

Fai attenzione alle limitazioni con il n. 2. Preferisco i POST al n. 1.

nota: i limiti sono discussi per

POST in Esiste una dimensione massima per il contenuto dei parametri POST?

OTTIENI C'è un limite alla lunghezza di una richiesta GET? e Dimensione massima dei parametri URL in _GET

ps questi limiti si basano sulle capacità del client (browser) e sul server (configurazione).


componente aggiuntivo: le route spiritose possono avere versioni (distinte tramite le intestazioni), quindi fornire funzionalità evolute senza la necessità di modificare il codice che consuma il codice rest-full (api) che scrivi come in restify -> cerca percorsi con versione
dgm

5

Secondo lo standard URI, il percorso è per parametri gerarchici e la query è per parametri non gerarchici. Ofc. può essere molto soggettivo ciò che è gerarchico per te.

In situazioni in cui più URI sono assegnati alla stessa risorsa, mi piace inserire i parametri - necessari per l'identificazione - nel percorso e i parametri - necessari per creare la rappresentazione - nella query. (Per me in questo modo è più facile da instradare.)

Per esempio:

  • /users/123 e /users/123?fields="name, age"
  • /users e /users?name="John"&age=30

Per ridurre la mappa mi piace usare i seguenti approcci:

  • /users?name="John"&age=30
  • /users/name:John/age:30

Quindi dipende davvero da te (e dal tuo router lato server) come costruire i tuoi URI.

nota: solo per menzionare questi parametri sono parametri di query. Quindi quello che stai veramente facendo è definire un linguaggio di query semplice. Per query complesse (che contengono operatori come e, o, maggiori di, ecc.) Ti suggerisco di usare un linguaggio di query già esistente. Le funzionalità dei modelli URI sono molto limitate ...


4

Come programmatore spesso sul lato client, preferisco l'argomento query. Inoltre, per me, separa il percorso dell'URL dai parametri, aumenta la chiarezza e offre maggiore estensibilità. Mi permette anche di avere una logica separata tra l'edificio URL / URI e il costruttore di parametri.

Mi piace quello che ha detto Manuel Aldana sull'altra opzione se c'è una specie di albero coinvolto. Riesco a vedere parti specifiche dell'utente tagliate in quel modo.


4

Non ci sono regole rigide e veloci, ma la regola empirica da un punto di vista puramente concettuale che mi piace usare può essere brevemente riassunta in questo modo: un percorso URI (per definizione) rappresenta una risorsa e i parametri della query sono essenzialmente modificatori su quella risorsa . Finora che probabilmente non aiuta ... Con un API REST si hanno i maggiori metodi di agire su una singola risorsa utilizzando GET, PUTe DELETE. Pertanto, se qualcosa deve essere rappresentato nel percorso o come parametro può essere ridotto al fatto che tali metodi abbiano senso per la rappresentazione in questione. Vuoi ragionevolmente fare PUTqualcosa su quel percorso e sarebbe semanticamente corretto farlo? Certo che puoiPUT qualcosa praticamente ovunque e piegare il back-end per gestirlo, ma dovresti esserloPUTciò che equivale a una rappresentazione della risorsa reale e non a una versione inutilmente contestualizzata di essa. Per le raccolte si può fare lo stesso con POST. Se volessi aggiungere a una particolare raccolta quale sarebbe un URL che abbia senso POST.

Questo lascia ancora alcune aree grigie in quanto alcuni percorsi potrebbero indicare quale ammontare per i figli delle risorse padre è alquanto discrezionale e dipende dal loro uso. L'unica linea che questo traccia è che qualsiasi tipo di rappresentazione transitiva dovrebbe essere fatto usando un parametro di query, poiché non avrebbe una risorsa sottostante.

In risposta all'esempio del mondo reale fornito nella domanda originale (API di Twitter), i parametri rappresentano una query transitiva che filtra sullo stato delle risorse (piuttosto che una gerarchia). In quel particolare esempio sarebbe del tutto irragionevole aggiungere alla raccolta rappresentata da quei vincoli, e inoltre quella query non sarebbe in grado di essere rappresentata come un percorso che avrebbe senso nei termini di un grafico a oggetti.

L'adozione di questo tipo di prospettiva orientata alle risorse può facilmente mappare direttamente sul grafico degli oggetti del modello di dominio e guidare la logica dell'API al punto in cui tutto funziona in modo molto pulito e in modo abbastanza auto-documentale una volta che scatta in modo chiaro. Il concetto può anche essere chiarito allontanandosi dai sistemi che utilizzano il routing URL tradizionale mappato su un modello di dati normalmente inadatto (ovvero un RDBMS). Apache Sling sarebbe sicuramente un buon punto di partenza. Il concetto di invio di attraversamenti di oggetti in un sistema come Zope fornisce anche un analogo più chiaro.


4

Ecco la mia opinione

I parametri di query vengono utilizzati come metadati per una richiesta. Agiscono come filtro o modificatore per una chiamata di risorsa esistente.

Esempio:

/calendar/2014-08-08/events

dovrebbe dare eventi di calendario per quel giorno.

Se vuoi eventi per una categoria specifica

/calendar/2014-08-08/events?category=appointments

o se hai bisogno di eventi di durata superiore a 30 minuti

/calendar/2014-08-08/events?duration=30

Una cartina di tornasole sarebbe quella di verificare se la richiesta può ancora essere servita senza parametri di query.


2

In genere tendo verso # 2, come argomento di query (ad es. / Api / resource? Parametro = valore).

Una terza opzione è quella di pubblicare effettivamente il parametro = valore nel corpo.

Questo perché funziona meglio per risorse multiparametriche ed è più estendibile per un uso futuro.

Non importa quale scegli, assicurati di sceglierne solo uno, non mescolare e abbinare. Ciò porta a un'API confusa.


2

Una "dimensione" di questo argomento è stata lasciata fuori ma è molto importante: ci sono momenti in cui le "migliori pratiche" devono venire a patti con la piattaforma che stiamo implementando o aumentando con le capacità REST.

Esempio pratico:

Molte applicazioni web oggigiorno implementano l'architettura MVC (Model, View, Controller). Presumono che venga fornito un determinato percorso standard, tanto più quando tali applicazioni web dispongono di un'opzione "Abilita URL SEO".

Solo per citare un'applicazione web abbastanza famosa: un negozio di e-commerce OpenCart. Quando l'amministratore abilita gli "URL SEO", si aspetta che gli URL vengano in un formato MVC abbastanza standard come:

http://www.domain.tld/special-offers/list-all?limit=25

Dove

  • special-offers è il controller MVC che deve elaborare l'URL (mostrando la pagina delle offerte speciali)

  • list-allè l'azione del controller o il nome della funzione da chiamare. (*)

  • limite = 25 è un'opzione, che indica che verranno visualizzati 25 elementi per pagina.

(*) list-allè un nome di funzione fittizia che ho usato per chiarezza. In realtà, OpenCart e la maggior parte dei framework MVC hanno una funzione predefinita, implicita (e generalmente omessa nell'URL) indexche viene chiamata quando l'utente desidera eseguire un'azione predefinita. Quindi l'URL del mondo reale sarebbe:

http://www.domain.tld/special-offers?limit=25

Con un'applicazione o una struttura frameworkd ora abbastanza standard simili a quelle sopra, spesso si ottiene un server Web ottimizzato per esso, che riscrive gli URL per esso (il vero "URL non SEO" sarebbe:) http://www.domain.tld/index.php?route=special-offers/list-all&limit=25.

Pertanto, come sviluppatore, devi affrontare l'infrastruttura esistente e adattare le tue "migliori pratiche", a meno che tu non sia l'amministratore di sistema, sappi esattamente come modificare una configurazione di riscrittura di Apache / NGinx (quest'ultima può essere brutta!) E così su.

Pertanto, l'API REST sarebbe spesso molto meglio seguendo gli standard dell'applicazione Web di riferimento, sia per coerenza con esso che facilità / velocità (e quindi risparmio di budget).

Per tornare all'esempio pratico sopra, un'API REST coerente sarebbe qualcosa con URL come:

http://www.domain.tld/api/special-offers-list?from=15&limit=25

o (URL non SEO)

http://www.domain.tld/index.php?route=api/special-offers-list?from=15&limit=25

con una combinazione di argomenti "percorsi formati" e argomenti "query formata".



0

È una domanda molto interessante.

Puoi usarli entrambi, non esiste una regola rigida su questo argomento, ma l'uso delle variabili del percorso URI presenta alcuni vantaggi:

  • Cache : la maggior parte dei servizi di cache Web su Internet non memorizza nella cache la richiesta GET quando contiene parametri di query. Lo fanno perché ci sono molti sistemi RPC che utilizzano richieste GET per modificare i dati nel server (fallire !! Get deve essere un metodo sicuro)

Ma se usi variabili di percorso, tutti questi servizi possono memorizzare nella cache le tue richieste GET.

  • Gerarchia : le variabili del percorso possono rappresentare la gerarchia: / Città / Via / Luogo

Fornisce all'utente maggiori informazioni sulla struttura dei dati.

Ma se i tuoi dati non hanno alcuna relazione gerarchica, puoi comunque utilizzare le variabili Path, usando virgola o punto e virgola:

/ Città / longitudine, latitudine

Di norma, utilizzare la virgola quando l'ordinamento dei parametri è importante, utilizzare i punti e virgola quando l'ordinamento non ha importanza:

/ IconGenerator / rosso; blu; verde

A parte questi motivi, ci sono alcuni casi in cui è molto comune usare le variabili della stringa di query:

  • Quando è necessario che il browser inserisca automaticamente le variabili del modulo HTML nell'URI
  • Quando hai a che fare con l'algoritmo. Ad esempio, il motore di Google utilizza stringhe di query:

http: // www.google.com/search?q=rest

Per riassumere, non esiste alcun motivo valido per utilizzare uno di questi metodi, ma ogni volta che è possibile, utilizzare le variabili URI.

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.