Best practice dell’API REST: dove inserire i parametri?

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

  1. Come parte del percorso dell’URL (cioè /api/resource/parametervalue )
  2. Come argomento di query (cioè /api/resource?parameter=value )

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

Esempio di mondo 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 migliore il design per inserire questi parametri nel percorso dell’URL?

Se ci sono buone pratiche documentate, non le ho ancora trovate. Tuttavia, ecco alcune linee guida che uso 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, tenderei verso un parametro del segmento di percorso. ad esempio /customer/232 dove 232 non è un ID cliente valido.

Se tuttavia si desidera restituire una lista vuota, quando il parametro non viene trovato, suggerisco di utilizzare i parametri della stringa di query. ad esempio /contacts?name=dave

Se un parametro interessa un’intera sottostruttura dello spazio URI, utilizzare un segmento di percorso. ad esempio un parametro di lingua /en/document/foo.txt versus /document/foo.txt?language=en

Preferisco che gli identificatori univoci si trovino in un segmento di percorso anziché 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 parametrizzare gli URI.

Risposta tardiva, ma aggiungerò alcune informazioni aggiuntive su ciò che è stato condiviso, ovvero che ci sono diversi tipi di “parametri” per una richiesta, e dovresti tenerne conto.

  1. Locatori – Ad esempio identificatori di risorse come ID o azione / vista
  2. Filtri: ad esempio, i parametri che forniscono una ricerca, ordinamento o restringimento del set di risultati.
  3. Stato – Ad esempio, identificazione della sessione, chiavi API, whatevs.
  4. Contenuto: es. Dati da memorizzare.

Ora diamo un’occhiata ai diversi punti 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)

In genere si desidera impostare lo stato nelle intestazioni o nei cookie, a seconda del tipo di informazioni di stato che è. Penso che tutti possiamo essere d’accordo su questo. Usa intestazioni http personalizzate (X-My-Header) se necessario.

Allo stesso modo, il Contenuto ha solo un luogo di appartenenza, che si trova nel corpo della richiesta, sia come stringhe di query o come contenuto http multipart e / o JSON. Questo è coerente con ciò che ricevi dal server quando ti manda il contenuto. Quindi non dovresti essere scortese e farlo in modo diverso.

Locatori come “id = 5” o “action = refresh” o “page = 2” avrebbero senso avere come percorso URL, come ad esempio mysite.com/article/5/page=2 dove in parte sai cosa è ogni parte dovrebbe significare (le basi come articolo e 5 significano ovviamente ottenere i dati di tipo articolo con id 5) e parametri aggiuntivi sono specificati come parte dell’URI. Possono essere nella forma di page=2 , o page/2 se si sa che dopo un certo punto nell’URI le “cartelle” sono valori-chiave accoppiati.

I filtri vanno sempre nella stringa di query, perché mentre fanno parte del trovare i dati giusti, sono lì solo per restituire un sottoinsieme o una modifica di ciò che i Locator restituiscono da soli. La ricerca in mysite.com/article/?query=Obama (sottoinsieme) è un filtro, e quindi è /article/5?order=backwards (modifica). Pensa a quello che fa, non solo 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 invece di puntare su quale risorsa vogliamo. Se invece decide quale parte specifica dell’articolo possiamo vedere ( mysite.com/article/5/view=summary ), allora è un localizzatore.

Ricorda, il restringimento di un insieme di risorse sta filtrando. Individuare qualcosa di specifico all’interno di una risorsa sta localizzando … duh. Il filtraggio dei sottoinsiemi può restituire qualsiasi numero di risultati (anche 0). L’individuazione 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 aiutato a dare alla gente alcuni momentjs di Eureka se sono stati persi su dove mettere le cose!

Dipende da un design. Non ci sono regole per URI a REST su HTTP (la cosa principale è che sono unici). Spesso si tratta di gusti e intuizioni …

Prendo il seguente approccio:

  • url path-element: la risorsa e il relativo path-element formano una directory traversal e una subresource (ad esempio / items / {id}, / users / items). Quando sei incerto chiedi ai tuoi colleghi, se pensano che attraversano e pensano in “un’altra directory”, il più probabile elemento di percorso è la scelta giusta
  • parametro url: quando non c’è davvero attraversamento (le risorse di ricerca con più parametri di query ne sono un esempio molto carino)

IMO i parametri 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.

Secondo l’implementazione REST,

1) Le variabili di percorso sono utilizzate per l’azione diretta sulle risorse, come un contatto o una canzone ex ..
OTTIENI etc / api / resource / {songid} o
GET etc / api / resource / {contactid} restituirà i rispettivi dati.

2) I parametri / argomenti di query sono usati per le risorse in-dirette come i metadati di un brano ex .., GET / api / resource / {songid}? Metadata = generi restituirà i dati dei generi per quella particolare canzone.

“Pack” e POST i tuoi dati rispetto al “contesto” che offre la risorsa universo-locatore, che significa # 1 per il vantaggio del localizzatore.

Presta attenzione ai limiti con # 2. Preferisco i POST al # 1.

nota: le limitazioni sono discusse per

POST in C’è una dimensione massima per il contenuto dei parametri POST?

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

ps questi limiti sono basati sulle funzionalità del client (browser) e sul server (configurazione).

Secondo lo standard URI, il percorso è per i parametri gerarchici e la query è per i 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 mettere i parametri – necessari per l’identificazione – nel percorso e i parametri – necessari per build 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 la riduzione della mappa mi piace utilizzare i seguenti approcci:

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

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

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

Come programmatore spesso sul lato client, preferisco l’argomento della query. Inoltre, per me, separa il percorso dell’URL dai parametri, aggiunge chiarezza e offre maggiore estensibilità. Mi consente inoltre di avere una logica separata tra l’URI / URI e il generatore di parametri.

Mi piace quello che ha detto manuel aldana sull’altra opzione se c’è una specie di albero coinvolto. Riesco a vedere le parti specifiche dell’utente che vengono smerigliate in questo modo.

Non ci sono regole dure e veloci, ma la regola empirica da un punto di vista puramente concettuale che mi piace usare può essere riassunta brevemente in questo modo: un percorso URI (per definizione) rappresenta una risorsa e i parametri di query sono essenzialmente modificatori su quella risorsa . Finora questo probabilmente non aiuta … Con un’API REST hai i principali metodi di agire su una singola risorsa usando GET , PUT e DELETE . Quindi, se qualcosa dovrebbe essere rappresentato nel percorso o come parametro può essere ridotto al fatto che questi metodi abbiano senso per la rappresentazione in questione. Vuoi ragionevolmente PUT qualcosa su quel percorso e sarebbe semanticamente corretto farlo? Ovviamente potresti PUT qualcosa ovunque e piegare il back-end per gestirlo, ma dovresti mettere in PUT ciò che equivale a una rappresentazione della risorsa reale e non una versione inutilmente contestualizzata di esso. Per le collezioni lo stesso può essere fatto con POST . Se si desidera aggiungere a una particolare raccolta, quale sarebbe l’URL che ha senso inserire in POST .

Ciò lascia ancora alcune aree grigie in quanto alcuni percorsi potrebbero indicare l’ammontare dei figli delle risorse dei genitori che è in qualche modo discrezionale e dipendente dal loro utilizzo. L’unica linea dura che questo disegna è che ogni tipo di rappresentazione transitiva dovrebbe essere fatto usando un parametro di query, poiché non avrebbe una risorsa sottostante.

In risposta all’esempio reale fornito nella domanda originale (API di Twitter), i parametri rappresentano una query transitiva che filtra sullo stato delle risorse (anziché su una gerarchia). In quel particolare esempio sarebbe del tutto irragionevole aggiungere alla collezione 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 grafo di oggetti.

L’adozione di questo tipo di prospettiva orientata alle risorse può facilmente mappare direttamente il grafico dell’object del modello di dominio e guidare la logica della tua API fino al punto in cui tutto funziona in modo molto pulito e in modo abbastanza auto-documentante, una volta che scatta in chiarezza. Il concetto può anche essere reso più chiaro allontanandosi dai sistemi che utilizzano il routing URL tradizionale mappato su un modello di dati normalmente inadeguato (ad esempio un RDBMS). Apache Sling sarebbe sicuramente un buon punto di partenza. Il concetto di inversione traversale di oggetti in un sistema come Zope fornisce anche un analogo più chiaro.

Ecco la mia opinione.

I parametri di query vengono utilizzati come metadati per una richiesta. Fungono da filtro o modificatore per una chiamata di risorse esistente.

Esempio:

/calendar/2014-08-08/events

dovrebbe dare eventi del 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 per verificare se la richiesta può ancora essere servita senza parametri di query.

In genere tendo al n. 2, come argomento di query (cioè / api / risorsa? Parametro = valore).

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

Questo perché funziona meglio con risorse multiparametriche ed è più estensibile per uso futuro.

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

Una “dimensione” di questo argomento è stata lasciata fuori, ma è molto importante: ci sono momentjs in cui le “migliori pratiche” devono entrare in sintonia con la piattaforma che stiamo implementando o aumentando con le funzionalità di REST.

Esempio pratico:

Molte applicazioni Web oggi implementano l’architettura MVC (Model, View, Controller). Assumono che venga fornito un determinato percorso standard, ancor più quando queste applicazioni web hanno l’opzione “Abilita URL SEO”.

Solo per citare un’applicazione web piuttosto famosa: un negozio di e-commerce OpenCart. Quando l’amministratore abilita gli “URL SEO” si aspetta che gli URL arrivino in un formato MVC piuttosto standard come:

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

Dove

  • special-offers è il controller MVC che elaborerà l’URL (mostrando la pagina delle offerte speciali)

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

  • limit = 25 è un’opzione, affermando che verranno mostrati 25 articoli per pagina.

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

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

Con una struttura o struttura frameworkd abbastanza simile a quella precedente, spesso si ottiene un server Web ottimizzato per questo, che riscrive gli URL per esso (il vero “URL non SEOed” potrebbe essere: http://www.domain.tld/index.php?route=special-offers/list-all&limit=25 ).

Quindi tu, come sviluppatore, hai a che fare con l’infrastruttura esistente e adattare le tue “migliori pratiche”, a meno che tu non sia l’amministratore di sistema, sai esattamente come modificare una configurazione di riscrittura di Apache / NGinx (quest’ultima può essere ctriggers!) E così sopra.

Pertanto, la tua API REST sarebbe spesso molto meglio seguire gli standard dell’applicazione web di riferimento, sia per coerenza con esso, sia per facilità / velocità (e quindi risparmio di budget).

Per tornare all’esempio pratico di cui sopra, un’API REST coerente potrebbe essere 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 un mix di argomenti “percorsi formati” e argomenti “interrogati”.

Vedo molte API REST che non gestiscono bene i parametri. Un esempio che emerge spesso è quando l’URI include informazioni di identificazione personale.

http://software.danielwatrous.com/design-principles-for-rest-apis/

Penso che una questione correlata sia quando un parametro non deve essere affatto un parametro, ma dovrebbe essere spostato nell’INTESTA o nel CORPO della richiesta.

È una domanda molto interessante

Puoi usarli entrambi, non ci sono regole rigide su questo argomento, ma usare le variabili del percorso URI ha alcuni vantaggi:

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

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

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

Fornisce all’utente maggiori informazioni sulla struttura dei dati.

Ma se i tuoi dati non hanno alcuna relazione gerarchica puoi ancora usare le variabili Path, usando la virgola o il punto e virgola:

/ Città / longitudine, latitudine

Come regola, utilizzare la virgola quando l’ordine dei parametri è importante, utilizzare il punto e virgola quando l’ordine non ha importanza:

/ IconGenerator / rosso; blu; verde

Oltre a questi motivi, ci sono alcuni casi in cui è molto comune utilizzare le variabili stringa di query:

  • Quando hai bisogno del browser per inserire 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: // http://www.google.com/search?q=rest

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