Convenzione REST URI - Nome singolare o plurale della risorsa durante la sua creazione


529

Sono nuovo di REST e ho notato che in alcuni servizi RESTful usano URI di risorse diverse per aggiornare / ottenere / cancellare e creare. Ad esempio

  • Crea - usando / risorse con il metodo POST (osservare il plurale) in alcuni punti usando / risorsa (singolare)
  • Aggiornamento - usando / resource / 123 con il metodo PUT
  • Ottieni - Utilizzo di / resource / 123 con il metodo GET

Sono un po 'confuso su questa convenzione di denominazione dell'URI. Cosa dovremmo usare singolare o plurale per la creazione di risorse? Quali dovrebbero essere i criteri nel decidere ciò?


9
Seguendo questo argomento, ho raccolto alcuni esempi di famose API REST in un articolo: inmensosofa.blogspot.com/2011/10/… .
jjmontes,

3
La conclusione che ho raggiunto dopo aver letto tutte le risposte seguenti: Usa sempre singolare perché (a) è coerente, (b) si associa direttamente ai nomi delle classi e delle tabelle singolari, (c) alcuni sostantivi plurali sono irregolari (imprevedibili) in inglese
Will Sheppard

Vedi questa risposta per un link a convenzioni di denominazione di tabelle singolari, e c'è un altro articolo che menziona questo problema esatto Dilemma dello sviluppatore dell'API di riposo - grazie @Sorter
Will Sheppard

Risposte:


281

La premessa dell'utilizzo /resourcesè che rappresenta "tutte" le risorse. Se lo fai GET /resources, probabilmente restituirai l'intera collezione. POSTANDO a /resources, stai aggiungendo alla raccolta.

Tuttavia, le singole risorse sono disponibili su / resource. Se lo fai GET /resource, probabilmente sbaglierai, poiché questa richiesta non ha alcun senso, mentre /resource/123ha perfettamente senso.

Utilizzando /resourceinvece di /resourcesè simile a come si farebbe questo se si stesse lavorando con, diciamo, un file system e una raccolta di file e /resourceè la "cartella" con i singoli 123, 456file in essa contenuti.

In nessun modo è giusto o sbagliato, scegli quello che ti piace di più.


55
Bella risposta! Ma le directory "predefinite" in Windows hanno nomi plurali . Come "Programmi", "Utenti", "Documenti", "Video" ecc. Inoltre ho incontrato nomi plurali negli URL dei siti Web molto più spesso.
Dmitry Gonchar,

50
la convenzione defacto praticamente la maggior parte delle persone e le API là fuori lo tengono sempre al plurale. Gli ID specificano UNA risorsa auto / ID
PositiveGuy

205
"In nessun modo è giusto o sbagliato, scegli quello che ti piace di più". Ah, la famosa frase che sento così spesso e mi stanco di sentire le persone. Le convenzioni contano e DOVREBBERO essere dibattute in modo costruttivo all'interno della comunità, ecco dove nascono soluzioni migliori e buone pratiche. Quando si utilizzano sia il plurale che il singolare per i nomi delle risorse negli URI, ciò complica il codice e l'API perché l'utente e il codice dietro l'API devono tener conto di ciò nei percorsi e nella logica per differenziare il singolo rispetto al plurale, mentre se si attacca semplicemente con il plurale per tutto il tempo non hai problemi.
Positivo

30
@TomaszPluskiewicz Hai perfettamente ragione che ai clienti non importa. Come sviluppatori di software che dovremmo cura - e per questo sono d'accordo con il commento di WTF che i dibattiti costruttivi su convenzione sono preziosi.
Travis D,

12
Quindi qualcuno può semplicemente rispondere con una sola parola e farla accettare, quindi non devo leggere tutto (di nuovo).
Ben George,

624

Per me è meglio avere uno schema che puoi mappare direttamente al codice (facile da automatizzare), principalmente perché il codice è quello che sarà ad entrambe le estremità.

GET  /orders          <---> orders 
POST /orders          <---> orders.push(data)
GET  /orders/1        <---> orders[1]
PUT  /orders/1        <---> orders[1] = data
GET  /orders/1/lines  <---> orders[1].lines
POST /orders/1/lines  <---> orders[1].lines.push(data) 

22
La difficoltà o la facilità di ciò è dovuta al mancato rispetto di HATEOS. Non dovrebbe importare se è plurale o singolare o altro. Dovresti rispettare gli uri inviati dal server e non "creare" i tuoi uri sul client. Quindi hai 0 mapping da fare per il tuo codice.
richard,

7
@richard Il client deve ancora eseguire il mapping. In HATEOS avrebbero dovuto mappare un nome che rappresenta la relazione (rel) con la costruzione dell'URI. Rel, method (verb) e Content-Type compongono quindi il supporto di risorse. Ciò non esclude la necessità di un buon design URI. Anche se il client potrebbe dare la precedenza al nome rel, gli sviluppatori dell'API hanno ancora bisogno di un buon standard leggibile dall'uomo per la costruzione dell'URI.

4
Questa è una risposta migliore secondo me. Tranne per il fatto che ho sempre preferito usare Singular invece del plurale. User.getList (), User.getById, User.delete ecc.
Monaco orientale

3
Mi piace la semplicità. La mappatura ha anche il vantaggio di rendere la documentazione e i test su percorsi incredibilmente facili da scrivere.
delos

5
Questo ha senso per me. Tuttavia, siamo il primo negozio di database, il che significa che generiamo codice e entità API dal nostro schema di database. E gli standard del database tendono a sostenere nomi di tabelle singolari, quindi stiamo andando con quello, ma ancora nella stessa logica di questa risposta.
André C. Andersen,

274

Non vedo nemmeno il punto di fare questo e penso che non sia il miglior design URI. Come utente di un servizio RESTful, mi aspetto che la risorsa dell'elenco abbia lo stesso nome, indipendentemente dal fatto che acceda all'elenco o alla risorsa specifica "nell'elenco". È necessario utilizzare gli stessi identificatori, indipendentemente dal fatto che si desideri utilizzare la risorsa elenco o una risorsa specifica.


69
Questa è la risposta migliore per quanto mi riguarda. Apprezzo che i progettisti di API apprezzino la correttezza linguistica di dire "ottieni la risorsa # 123", ma è una seccatura di codifica aggiuntiva quando si scrivono i client dell'API e la documentazione di aiuto. (GET / api / people vs. GET / api / person / 123? Euuuchh.) .... invece di pensarlo come "get resource # 123", esprimilo nella tua testa come "get from the collection of resources that corrisponde a # 123 ".
Warren Rumak,

5
Distinguere le risorse plurali / singolari non riguarda la correttezza linguistica ma la scala. / impiegati / 12 mi legge come il sottoinsieme della risorsa dei dipendenti con ID '12' (potrebbe significare qualsiasi cosa, ad esempio una query di ricerca salvata su impiegati licenziati di recente). Se leggi quanto sopra come impiegato con ID "12", come rappresenteresti il ​​sottoinsieme? L'unica opzione è rendere il minerale più complesso dell'URI distinguendo le raccolte contenenti oggetti dagli oggetti stessi (cioè singolare vs plurale).
Erik,

9
Scegliere / impiegati / 12 per rappresentare una query di ricerca su impiegati licenziati di recente (o qualsiasi sottoinsieme) sarebbe una cattiva progettazione, penso. Se si desidera rappresentare sottoinsiemi di qualsiasi tipo, suggerisco di introdurli come risorse (con nomi propri) a sé stanti.
Jan Deinhard,

3
Questo non ha nulla a che fare con la comprensibilità per i clienti. Si tratta di affrontare cose diverse con URL diversi. E essere in grado di rispondere a tutti i metodi HTTP senza essere in conflitto. Puoi avere una risorsa che è una raccolta di elementi e una risorsa che rappresenta un elemento stesso. Per quanto mi riguarda, la risorsa delle raccolte potrebbe essere esempio.org/166316e2-e1 e un elemento particolare in quella raccolta esempio.org/20d68348-ccc-001c4200de . Il client non dovrebbe costruire URL (che ovviamente non si ridimensiona, non è RESTful ed è a questo che servono i tipi di relazione di collegamento).
Erik

4
Se non ritieni che gli URL arbitrari siano belli, sentiti libero di identificare una risorsa di raccolta con un nome plurale e un singolo articolo con un nome singolare. Se non ti piacciono gli URL in inglese e il tuo linguaggio naturale non supporta quel modo di notazione singolare / plurale, usa qualcos'altro per definirlo nella tua lingua preferita, suppongo che tutte le lingue ti consentano in qualche modo di distinguere '/ the-collection-of- bla / 2321 'contro' bla / 61 'per iscritto. E ognuna di queste due diverse risorse rappresentano risultati completamente diversi quando si inviano GET / PUT / DELETE / POST / PATCH e altri.
Erik,

77

Plurale

  • Semplice : tutti gli URL iniziano con lo stesso prefisso
  • Logico -orders/ ottiene un elenco indice di ordini.
  • Standard : lo standard più ampiamente adottato, seguito dalla stragrande maggioranza delle API pubbliche e private.

Per esempio:

GET /resources - restituisce un elenco di elementi delle risorse

POST /resources - crea uno o più elementi di risorse

PUT /resources - aggiorna uno o più elementi delle risorse

PATCH /resources - aggiorna parzialmente uno o più elementi di risorse

DELETE /resources - elimina tutti gli elementi delle risorse

E per gli elementi a risorsa singola:

GET /resources/:id- restituisce un elemento risorsa specifico in base al :idparametro

POST /resources/:id - crea un elemento di risorsa con ID specificato (richiede la convalida)

PUT /resources/:id - aggiorna un elemento di risorsa specifico

PATCH /resources/:id - aggiorna parzialmente un elemento di risorsa specifico

DELETE /resources/:id - elimina un elemento risorsa specifico

Ai sostenitori del singolare, la pensi in questo modo: chiederesti a qualcuno ordere ti aspetti una cosa o un elenco di cose? Quindi perché dovresti aspettarti che un servizio restituisca un elenco di cose quando digiti /order?


10
Singolare : nel caso in cui una parte del tuo sistema sia un solo oggetto (0-1, esiste o no) ad es. Utenti / 1 / avatar puoi usare un modulo singolare per etichettare questo singolo oggetto (ad es. Avatar) - esempio più dettagliato qui: stackoverflow .com / a / 38296217/860099 . A proposito - bella risposta :)
Kamil Kiełczewski

Che dire del mapping ai nomi di classi e tabelle, che dovrebbero essere singolari? (vedi altra risposta )
Will Sheppard il

@WillSheppard - I nomi delle classi sono i migliori in forma singolare e i nomi delle tabelle sono i migliori in forma plurale. Ad esempio, Orderè un buon nome per una classe che si occupa di singole istanze di oggetti che si riferiscono a un ordine. OrderListè un nome per una classe che si occupa di più Orderistanze. Orders Tableè un buon nome per una tabella di database di molti ordini.
Eric Knudtson,

Voglio ottenere / ordini ma voglio solo / 1
jim smith

@ jim-smith quindi perché non richiedi / 1 dalla raccolta di utenti con GET / users / 1?
Rohmer,

49

Singolare

Convenienza Le cose possono avere nomi plurali irregolari. A volte non ne hanno uno. Ma i nomi singolari sono sempre lì.

ad es. CustomerAddress su CustomerAddresses

Considera questa risorsa correlata.

Questo /order/12/orderdetail/12è più leggibile e logico di/orders/12/orderdetails/4 .

Tabelle database

Una risorsa rappresenta un'entità come una tabella di database. Dovrebbe avere un nome logico singolare. Ecco la risposta sui nomi delle tabelle.

Mappatura delle classi

Le lezioni sono sempre singolari. Gli strumenti ORM generano tabelle con gli stessi nomi dei nomi di classe. Man mano che vengono utilizzati sempre più strumenti, i nomi singolari stanno diventando uno standard.

Ulteriori informazioni sul dilemma dello sviluppatore di un'API REST


39
I nomi singolari sono sempre lì /clothe/12/trouser/34 :)
Gert Arnold,

18
@GertArnold la parola clotheè un verbo. Le API di riposo generalmente si attaccano ai nomi quando parlano di risorse e usano i verbi per descrivere le azioni. La forma singolare è clout, ma è arcaica e verosimilmente verrebbe sostituita da garment.
Steve Buzonas,

@SteveBuzonas E per pantaloni e occhiali da sole?
Koray Tugay

32

Mentre la pratica più diffusa sono le API RESTful in cui si usano i plurali /api/resources/123, ad esempio , c'è un caso speciale in cui trovo l'uso di un nome singolare più appropriato / espressivo dei nomi plurali. È il caso delle relazioni individuali. In particolare se l'elemento di destinazione è un oggetto valore (nel paradigma del design guidato dal dominio).

Supponiamo che ogni risorsa abbia uno-a-uno accessLogche potrebbe essere modellato come un oggetto valore, cioè non un'entità, quindi nessun ID. Potrebbe essere espresso come /api/resources/123/accessLog. I soliti verbi (POST, PUT, DELETE, GET) esprimono in modo appropriato l'intento e anche il fatto che la relazione sia davvero uno a uno.


4
Bel tentativo. Ma sarebbe meglio come "accessLogEntries". :-)
Tom Russell

8
@TomRussell perché? Le implicazioni di questo sono importanti. Capisco perché dovresti usare il plurale anche quando accedi a una risorsa da un identificatore, ma per un molti-a-uno o uno-a-uno è abbastanza fuorviante. Si consideri un API che gestisce i membri del personale per un'azienda multi-location. Ogni membro del personale lavora in una posizione. GET /users/123/locationdovrebbe recuperare la posizione in cui l'utente lavora. Non è GET /users/123/locationsdavvero fuorviante come consumatore?
Carrie Kendall

1
@CarrieKendall Vedo il tuo punto. Poiché accessLogè modellato come un attributo o valore, piuttosto che un'entità, dovrebbe essere singolare. Se ti viene dato un eccesso di ingegneria, una voce di registro sarebbe un'entità e avresti /api/accessLogEntries?resource=123.
Tom Russell,

D'accordo, sebbene, penso che rompa la convenzione di pluralizzare tutte le cose. È difficile. Per me, è importante che un'API sia diretta, cioè la documentazione dovrebbe integrare un'implementazione già diretta.
Carrie Kendall,

Sono più un programmatore che una persona di sistemi o database, quindi mi piace un'API che racconta una storia piuttosto che aderire alla convenzione. Tuttavia, le implicazioni per la documentazione automatizzata sono reali.
Tom Russell,

26

Perché non seguire la tendenza prevalente dei nomi delle tabelle del database, in cui una forma singolare è generalmente accettata? Ci sono stato, fatto questo - riutilizziamo.

Dilemma di denominazione delle tabelle: nomi singolari e plurali


8
Das Auto è molto meglio di Die Autos. Inoltre, le convenzioni plurali inglesi non sono coerenti.
FlavorScape

7
Lo spazio dei nomi delle risorse è una questione di semantica, non di implementazione. Quindi, usando l'analogia delle tabelle DB, non è molto fortunato. Inoltre, quando lavori con DB-s stai manipolando solo le tabelle, anche se ovviamente puoi influenzare il contenuto (righe), ma in REST non c'è alcun vincolo per manipolare direttamente una singola risorsa.
Arpadf,

3
Penso che questa sia una buona analogia, ma è più importante che decidere se passare al singolare o al plurale sia coerente con qualunque cosa tu scelga. Non inserirai Utenti e quindi selezionerai da Utente. La stessa regola dovrebbe applicarsi alle risorse REST: non rinominarle a seconda di ciò che stai facendo.
Todd Menier

3
Non sono solo i nomi delle tabelle, è anche paragonabile ai nomi delle classi in OO (la mia classe si chiamerebbe Cliente non Clienti).
bytedev,

In questo caso, la semantica è troppo importante per accettare semplicemente tendenze "già definite"
Cattani Simone

19

Sono sorpreso di vedere che così tante persone salterebbero sul carro del sostantivo plurale. Durante l'implementazione di conversioni dal singolare al plurale, ti occupi dei nomi plurali irregolari? Ti piace il dolore?

Vedi http://web2.uvcs.uvic.ca/elc/studyzone/330/grammar/irrplu.htm

Esistono molti tipi di plurale irregolare, ma questi sono i più comuni:

Tipo di nome Formazione del plurale Esempio

Ends with -fe   Change f to v then Add -s   
    knife   knives 
    life   lives 
    wife   wives
Ends with -f    Change f to v then Add -es  
    half   halves 
    wolf   wolves
    loaf   loaves
Ends with -o    Add -es 
    potato   potatoes
    tomato   tomatoes
    volcano   volcanoes
Ends with -us   Change -us to -i    
    cactus   cacti
    nucleus   nuclei
    focus   foci
Ends with -is   Change -is to -es   
    analysis   analyses
    crisis   crises
    thesis   theses
Ends with -on   Change -on to -a    
    phenomenon   phenomena
    criterion   criteria
ALL KINDS   Change the vowel or Change the word or Add a different ending   
     man   men
     foot   feet
     child   children
     person   people
     tooth   teeth
     mouse   mice
 Unchanging Singular and plural are the same    
     sheep deer fish (sometimes)

5
Non capisco la preoccupazione qui. Non dovremmo cambiare dal singolare al plurale programmaticamente. La maggior parte delle forme plurali sopra riportate sono ben note e non dovrebbero essere motivo di preoccupazione. Se qualcuno ha una scarsa conoscenza dell'inglese, scriverà in modo errato qualsiasi parte della tua variabile. Inoltre, seguendo la tua logica, mi consiglia di utilizzare anche moduli singolari per fare riferimento a raccolte anche nel codice sorgente?
Kishor Borate,

1
Ci sono parole inglesi che sono irregolari al punto in cui è spesso un problema anche all'interno dell'Anglosfera e sono termini comunemente usati come indice / indici / indici, vertice / vertici / vertici, matrice / matrici / matrici, raggio / raggi / raggi, ecc. Non vedo il punto nel rendere plurali i percorsi REST comunque, perché se sono tutti costantemente singolari, è solo più ovvio per tutti.
dannatamente

@kishorborate, L'uso del plurale come URI è più soggetto a errori, anche per i madrelingua inglesi. Come dannatamente indicato, i plurali come indice / indici / indici stanno introducendo più problemi. E ci sono innumerevoli nomi. Mischiare nomi innumerevoli con plurali è un altro problema. Perché è più difficile per i programmatori dedicare più tempo a questi? Suggerisco di usare i singolari per tutto. Se esiste un / {id}, l'API dovrebbe restituire un singolo record. Se non esiste un / {id} che segue, l'API dovrebbe restituire la raccolta.
Daming Fu,

3
@DamingFu La risorsa singolare potrebbe non avere sempre un ID associato ad essa. per esempio. / user / {id} / nickName Guardandolo, non è chiaro se restituirà un elenco di nickname o nickname singolo? Pertanto, le API sono più intuitive quando utilizza forme plurali. Sì, poche parole avranno forme plurali irregolari. Per qualcuno che sta leggendo la forma plurale, non è un problema. È un problema solo quando si scrive la firma dell'API. Ma la frequenza di tali parole non è elevata, inoltre, trovare la forma plurale di qualsiasi parola non richiede tempo. È un compromesso che dovremmo accettare, per rendere le API più intuitive.
Kishor Borate,

15

Dal punto di vista del consumatore API, gli endpoint dovrebbero essere prevedibili

Idealmente...

  1. GET /resources dovrebbe restituire un elenco di risorse.
  2. GET /resource dovrebbe restituire un codice di stato di livello 400.
  3. GET /resources/id/{resourceId} dovrebbe restituire una raccolta con una risorsa.
  4. GET /resource/id/{resourceId} dovrebbe restituire un oggetto risorsa.
  5. POST /resources dovrebbe creare in batch risorse.
  6. POST /resource dovrebbe creare una risorsa.
  7. PUT /resource dovrebbe aggiornare un oggetto risorsa.
  8. PATCH /resource dovrebbe aggiornare una risorsa pubblicando solo gli attributi modificati.
  9. PATCH /resources dovrebbe aggiornare in batch le risorse pubblicando solo gli attributi modificati.
  10. DELETE /resourcesdovrebbe eliminare tutte le risorse; sto scherzando: 400 codice di stato
  11. DELETE /resource/id/{resourceId}

Questo approccio è il più flessibile e ricco di funzionalità, ma anche il più dispendioso in termini di tempo per lo sviluppo. Quindi, se hai fretta (che è sempre il caso dello sviluppo del software), dai un nome al tuo endpoint resourceo alla forma plurale resources. Preferisco la forma singolare perché ti dà la possibilità di introspettare e valutare programmaticamente poiché non tutte le forme plurali terminano in 's'.

Detto questo, per qualsiasi motivo lo sviluppatore della pratica più comunemente usato abbia scelto è usare la forma plurale. Questo è in definitiva il percorso che ho scelto e se guardi le apis popolari come githube twitter, questo è quello che fanno.

Alcuni criteri per decidere potrebbero essere:

  1. Quali sono i miei vincoli temporali?
  2. Quali operazioni consentirò ai miei consumatori di fare?
  3. Che aspetto hanno il payload di richiesta e risultato?
  4. Voglio essere in grado di utilizzare reflection e analizzare l'URI nel mio codice?

Quindi dipende da te. Tutto ciò che fai è coerente.


1
Sembra che la forma plurale sia stata scelta perché gli sviluppatori sembrano supporre che tutte le risorse siano intrinsecamente parte di alcune raccolte. Tuttavia, la "convenzione accettata" sembra indicare che POST /usersdovrebbe creare un singolo utente, aggiungendolo alla raccolta. Non sono d'accordo. POST /usersdovrebbe creare un elenco di utenti (anche se si tratta di un elenco di 1), dove come POST /userdovrebbe creare esattamente un utente. Non vedo alcun motivo per cui endpoint di risorse sia plurali che singolari non possano coesistere. Descrivono comportamenti diversi e non dovrebbero sorprendere nessuno della loro funzione.
schiaccia il

Non esiste una convenzione per specificare un ID risorsa nel percorso? In tal caso, sembra essere ampiamente trascurato. Ad esempio, POST users/<id>creerebbe un nuovo utente.
Tom Russell,

1
@TomRussell di solito il server crea l'id, quindi non si conosce ancora l'id a POST.
Alex,

3
@TomRussell, quando il client determina (una specie di) id durante la creazione di una nuova risorsa, è più comune usarlo PUT /users/<id>invece di POST. POSTha l'interpretazione "aggiungi questo alla raccolta e determina l'id come parte di quello". PUTha l'interpretazione "aggiorna (o aggiungi) questa risorsa con questo id". Vedi restcookbook.com/HTTP%20Methods/put-vs-post per una spiegazione più lunga di questo principio.
Jochem Schulenklopper,

Non credo che il confronto con l'API di Twitter sia corretto in quanto usano il modulo plurale per tutti i loro endpoint. Non mescolano Plural e Singular per gli stessi elementi.
Andrew T Finnell,

7

I miei due centesimi: i metodi che passano il loro tempo cambiando dal plurale al singolare o viceversa sono una perdita di cicli della CPU. Potrei essere di vecchia scuola, ma ai miei tempi come se le cose fossero chiamate uguali. Come posso cercare metodi riguardanti le persone? Nessuna espressione regolare coprirà sia la persona che le persone senza effetti collaterali indesiderati.

I plurali inglesi possono essere molto arbitrari e ingombrano inutilmente il codice. Attenersi a una convenzione di denominazione. I linguaggi del computer dovevano riguardare la chiarezza matematica, non la mimica del linguaggio naturale.


2
Questo indirizza il codice che tenta di "generare automaticamente / manipolare" gli endpoint (ci sono molte librerie supposte che assumono pluralità / singolarità e tentano di mappare); tuttavia, ciò si applica ai nomi di endpoint scelti in modo esplicito non più della scelta della parola giusta (indipendentemente da come sia pluralizzata).
user2864740

6

Preferisco usare la forma singolare sia per semplicità che per coerenza.

Ad esempio, considerando il seguente URL:

/ Cliente / 1

Tratterò il cliente come raccolta del cliente, ma per semplicità, la parte della raccolta viene rimossa.

Un altro esempio:

/ Attrezzature / 1

In questo caso, le apparecchiature non sono la forma plurale corretta. Quindi trattarlo come una raccolta di attrezzature e rimuovere la raccolta per semplicità lo rende coerente con il caso del cliente.


2
POST / cliente sembra che sostituirà il solo ed unico cliente. Questo è il mio più grande dolore con l'uso di nomi di risorse singolari.
Andrew T Finnell,

2
@ andrew-t-finnell Non POST /customerdovresti fare proprio la cosa: inserire un singolo cliente?
donmutti,

Inserisce un singolo cliente in una raccolta di clienti. POST /customermi legge come se fosse POSTO per il thecliente. Non una raccolta di clienti. Tuttavia, ammetto che Plural è una preferenza. Finché non sono mescolati come ha fatto l'altra risposta. Sarebbe incredibilmente confuso.
Andrew T Finnell,

"POST 'al cliente" non ha senso in questo caso. Il POST non si sostituisce, si inserisce. Forse se fosse POST / cliente / 1 potrei vedere il dilemma, ma anche questo non ha molto senso dal punto di vista del RESTO, perché cosa stai inserendo? Sarebbe / cliente / 1 / fattura o / cliente / 1 / ricevuta, ecc.
dannatamente

5

Un id in una route dovrebbe essere visualizzato come un indice di un elenco e la denominazione dovrebbe procedere di conseguenza.

numbers = [1, 2, 3]

numbers            GET /numbers
numbers[1]         GET /numbers/1
numbers.push(4)    POST /numbers
numbers[1] = 23    UPDATE /numbers/1

Ma alcune risorse non usano gli ID nei loro percorsi perché ce n'è solo uno o un utente non ha mai accesso a più di uno, quindi quelli non sono elenchi:

GET /dashboard
DELETE /session
POST /login
GET /users/{:id}/profile
UPDATE /users/{:id}/profile

4

Con le convenzioni di denominazione, di solito è sicuro dire "basta sceglierne uno e attenersi ad esso", il che ha senso.

Tuttavia, dopo aver dovuto spiegare REST a molte persone, rappresentare gli endpoint come percorsi su un file system è il modo più espressivo per farlo.
È apolide (i file esistono o non esistono), gerarchico, semplice e familiare: sai già come accedere ai file statici, localmente o via http.

E in quel contesto, le regole linguistiche possono arrivare solo a quanto segue:

Una directory può contenere più file e / o sottodirectory, pertanto il suo nome deve essere in forma plurale.

E questo mi piace.
Anche se, d'altra parte, è la tua directory, puoi chiamarla "a-resource-or-multiple-resources" se è quello che vuoi. Questa non è davvero la cosa importante.

Ciò che è importante è che se si inserisce un file denominato "123" in una directory denominata "risorse" (risultante /resourceS/123), non è possibile aspettarsi che sia accessibile tramite /resource/123.

Non cercare di renderlo più intelligente di quanto deve essere: passare da plurale a singolare a seconda del numero di risorse a cui stai attualmente accedendo potrebbe essere esteticamente piacevole per alcuni, ma non è efficace e non ha senso in un sistema gerarchico .

Nota: tecnicamente, puoi creare "collegamenti simbolici", in modo che sia /resources/123possibile accedervi anche tramite /resource/123, ma il primo deve ancora esistere!


3

Date un'occhiata a Google 's API Design Guide: Nomi risorse per prendere un altro sulle risorse di denominazione.

In breve:

  • Le collezioni sono chiamate con plurali.
  • Le singole risorse sono denominate con una stringa.
|--------------------------+---------------+-------------------+---------------+--------------|
| API Service Name         | Collection ID | Resource ID       | Collection ID | Resource ID  |
|--------------------------+---------------+-------------------+---------------+--------------|
| //mail.googleapis.com    | /users        | /name@example.com | /settings     | /customFrom  |
| //storage.googleapis.com | /buckets      | /bucket-id        | /objects      | /object-id   |
|--------------------------+---------------+-------------------+---------------+--------------|

Vale la pena leggere se stai pensando a questo argomento.


2

L'uso del plurale per tutti i metodi è più pratico almeno in un aspetto: se stai sviluppando e testando un'API di risorse usando Postman (o uno strumento simile), non è necessario modificare l'URI quando passi da GET a PUT a POST ecc. .


1
Non è un argomento per me poiché Postman offre raccolte, quindi puoi salvare tutte le risorse come elementi di raccolta diversi e testarle singolarmente. Tutto quello che fai è selezionare la risorsa dalla raccolta, non è necessario modificare i parametri / metodi / ecc ogni volta.
Wirone,

1

Entrambe le rappresentazioni sono utili. Ho usato singolare per comodità per un po 'di tempo, l'inflessione può essere difficile. La mia esperienza nello sviluppo di API REST rigorosamente singolari, gli sviluppatori che consumano l'endpoint mancano di certezza su quale possa essere la forma del risultato. Ora preferisco usare il termine che meglio descrive la forma della risposta.

Se tutte le tue risorse sono di alto livello, puoi cavartela con rappresentazioni singolari. Evitare l'inflessione è una grande vittoria.

Se stai facendo qualsiasi tipo di deep linking per rappresentare query sulle relazioni, gli sviluppatori che scrivono contro la tua API possono essere aiutati da una convenzione più rigorosa.

La mia convenzione è che ogni livello di profondità in un URI sta descrivendo un'interazione con la risorsa padre e l'URI completo dovrebbe implicitamente descrivere ciò che viene recuperato.

Supponiamo di avere il seguente modello.

interface User {
    <string>id;
    <Friend[]>friends;
    <Manager>user;
}

interface Friend {
    <string>id;
    <User>user;
    ...<<friendship specific props>>
}

Se avessi bisogno di fornire una risorsa che consenta a un cliente di ottenere il gestore di un determinato amico di un determinato utente, potrebbe assomigliare a:

GET /users/{id}/friends/{friendId}/manager

Di seguito sono riportati alcuni altri esempi:

  • GET /users - elenca le risorse utente nella raccolta utenti globale
  • POST /users - crea un nuovo utente nella raccolta di utenti globali
  • GET /users/{id} - recuperare un utente specifico dalla raccolta di utenti globali
  • GET /users/{id}/manager - ottenere il gestore di un utente specifico
  • GET /users/{id}/friends - Ottieni l'elenco degli amici di un utente
  • GET /users/{id}/friends/{friendId} - ottenere un amico specifico di un utente
  • LINK /users/{id}/friends - aggiungi un'associazione di amici a questo utente
  • UNLINK /users/{id}/friends - rimuovere un'associazione di amici da questo utente

Notare come ogni livello è associato a un genitore su cui può essere agito. L'uso di genitori diversi per lo stesso oggetto è controintuitivo. Il recupero di una risorsa in GET /resource/123non lascia alcuna indicazione sul fatto che la creazione di una nuova risorsa debba essere effettuata inPOST /resources


1

So che la maggior parte delle persone sta decidendo se usare il plurale o il singolare. Il problema che non è stato risolto qui è che il cliente dovrà sapere quale si sta utilizzando e è sempre probabile che commetta un errore. Ecco da dove viene il mio suggerimento.

Che ne dici di entrambi? E con ciò intendo usare singolare per l'intera API e quindi creare percorsi per inoltrare le richieste fatte in forma plurale alla forma singolare. Per esempio:

GET  /resources     =     GET  /resource
GET  /resources/1   =     GET  /resource/1
POST /resources/1   =     POST /resource/1
...

Ottieni l'immagine. Nessuno ha torto, il minimo sforzo e il cliente lo farà sempre bene.


1
Se stai eseguendo 302 reindirizzamenti e la cache memorizza tutto due volte, hai impostato la cache in modo errato. La cache non dovrebbe memorizzare 302 reindirizzamenti.
wynnset,

2
Se il tuo client usa sempre /resourcese viene sempre reindirizzato /resource, hai sbagliato. Se qualcun altro utilizza la tua API, può utilizzare direttamente l'URL corretto o essere reindirizzato (che funziona ma è sbagliato) ed è stato tu che hai aperto nel modo sbagliato.
maaartinus,

Non sono sicuro di cosa tu voglia dire "sbagliato" - è molto soggettivo. Non è proprio sbagliato perché funziona.
wynnset,

Ciò aumenta i costi di manutenzione, i costi di comprensione e la quantità di codice richiesta.
Will Sheppard,

1

Non mi piace vedere la {id}parte degli URL che si sovrappone alle risorse secondarie, dal momento idche teoricamente potrebbe esserci qualsiasi cosa e ci sarebbe ambiguità. Sta mescolando concetti diversi (identificatori e nomi delle risorse secondarie).

Problemi simili sono spesso visto in enumcostanti o una cartella di strutture, dove i diversi concetti sono misti (ad esempio, quando si dispone di cartelle Tigers, Lionse Cheetahs, e poi anche una cartella denominata Animalsallo stesso livello - questo non ha senso, come uno è un sottoinsieme della altro).

In generale, penso che l'ultima parte nominata di un endpoint dovrebbe essere singolare se si tratta di una singola entità alla volta, e plurale se si tratta di un elenco di entità.

Quindi endpoint che riguardano un singolo utente:

GET  /user             -> Not allowed, 400
GET  /user/{id}        -> Returns user with given id
POST /user             -> Creates a new user
PUT  /user/{id}        -> Updates user with given id
DELETE /user/{id}      -> Deletes user with given id

Quindi esiste una risorsa separata per eseguire query sugli utenti, che generalmente restituiscono un elenco:

GET /users             -> Lists all users, optionally filtered by way of parameters
GET /users/new?since=x -> Gets all users that are new since a specific time
GET /users/top?max=x   -> Gets top X active users

E qui alcuni esempi di una sotto-risorsa che si occupa di un utente specifico:

GET /user/{id}/friends -> Returns a list of friends of given user

Fai amicizia (link da molti a molti):

PUT /user/{id}/friend/{id}     -> Befriends two users
DELETE /user/{id}/friend/{id}  -> Unfriends two users
GET /user/{id}/friend/{id}     -> Gets status of friendship between two users

Non c'è mai alcuna ambiguità e la denominazione plurale o singolare della risorsa è un suggerimento per l'utente cosa possono aspettarsi (elenco o oggetto). Non ci sono restrizioni su ids, teoricamente rendendo possibile avere un utente con l'id newsenza sovrapposizioni con un nome (potenziale futuro) della sotto-risorsa.


1

Usa Singular e approfitta della convenzione inglese che si vede ad esempio in "Elenco società".

Molte cose leggono in questo modo: "Book Case", "Dog Pack", "Art Gallery", "Film Festival", "Car Lot", ecc.

Ciò corrisponde comodamente al percorso dell'URL da sinistra a destra. Tipo di oggetto a sinistra. Imposta il tipo a destra.

Recupera GET /usersmai davvero un insieme di utenti? Non solitamente. Recupera un set di matrici che contengono una chiave e forse un nome utente. Quindi non lo è davvero /users. È un indice di utenti, o un "indice di utenti", se vuoi. Perché non chiamarlo così? È un /user/index. Dato che abbiamo chiamato il tipo di set, possiamo avere più tipi che mostrano diverse proiezioni di un utente senza ricorrere a parametri di query, ad esempio user/phone-listo /user/mailing-list.

E l'utente 300? È ancora /user/300.

GET /user/index
GET /user/{id}

POST /user
PUT /user/{id}

DELETE /user/{id}

In conclusione, HTTP può avere una sola risposta a una singola richiesta. Un percorso fa sempre riferimento a qualcosa di singolare.


-1

Per me i plurali manipolano la collezione , mentre i singolari manipolano l' oggetto all'interno di quella collezione.

La raccolta consente i metodi GET / POST / DELETE

L'elemento consente i metodi GET / PUT / DELETE

Per esempio

POST su / studenti aggiungeranno un nuovo studente nella scuola.

DELETE on / studenti rimuoverà tutti gli studenti nella scuola.

ELIMINA su / studente / 123 rimuoverà lo studente 123 dalla scuola.

Potrebbe sembrare poco importante, ma alcuni ingegneri a volte dimenticano l'id. Se il percorso era sempre plurale ed eseguiva un ELIMINA, potresti cancellare accidentalmente i tuoi dati. Considerando che manca l'id sul singolare restituirà un percorso 404 non trovato.

Per espandere ulteriormente l'esempio se l'API dovesse esporre più scuole, allora qualcosa di simile

ELIMINA su / scuola / abc / studenti rimuoverà tutti gli studenti nella scuola abc.

La scelta della parola giusta a volte è una sfida da sola, ma mi piace mantenere la pluralità per la collezione. Ad esempio cart_itemso si cart/itemssente bene. Al contrario cart, eliminando , elimina l'oggetto carrello stesso e non gli oggetti all'interno del carrello;).


Questo non dovrebbe essere diviso è / cart e / cart / item (s) comunque? Quindi puoi indirizzare l'intero carrello (ad es. Con una cancellazione) o singoli articoli?
Rob Grant

@RobertGrant Non sarebbe "/ carts / items / 123"? (es. perché "carrello" e non "carrelli" è la regola "sempre plurale"?)
user2864740

1
Direi che se viene registrato il codice di produzione che è in grado di eseguire una cancellazione degli articoli del carrello di tutti, ci sono problemi più grandi della convenzione di denominazione. Il probabile cappuccio che ricorderebbero di una "s" su un documento d'identità è molto meno.
Andrew T Finnell,

qualcuno creerebbe mai un endpoint che elimina semplicemente un'intera raccolta? Mi sembra estremamente pericoloso, e probabilmente anche perché REST non supporta davvero le eliminazioni batch. (dovresti avvolgere l'array in un oggetto). Se avessi assolutamente bisogno di un endpoint per eliminare un'intera raccolta, mi assicurerei che l'URI fosse davvero univoco e sicuramente non simile al POST
cnps,

-1

Che ne dite di:

/resource/(non /resource)

/resource/ significa che è una cartella contenente qualcosa chiamato "risorsa", è una cartella "resouce".

E penso anche che la convenzione di denominazione delle tabelle del database sia la stessa, ad esempio una tabella chiamata "utente" è una "tabella utente", contiene qualcosa chiamato "utente".


-2

Preferisco usare sia il plurale ( /resources) che il singolare (/resource/{id} ) perché penso che separi più chiaramente la logica tra lavorare sulla raccolta di risorse e lavorare su una singola risorsa.

Come importante effetto collaterale di ciò, può anche aiutare a impedire a qualcuno di utilizzare l'API in modo errato. Ad esempio, considera il caso in cui un utente tenta erroneamente di ottenere una risorsa specificando l'id come parametro come questo:

GET /resources?Id=123

In questo caso, dove utilizziamo la versione plurale, molto probabilmente il server ignorerà il parametro Id e restituirà l'elenco di tutte le risorse. Se l'utente non sta attento, penserà che la chiamata è andata a buon fine e utilizzerà la prima risorsa nell'elenco.

D'altra parte, quando si utilizza la forma singolare:

GET /resource?Id=123

molto probabilmente il server restituirà un errore perché l'id non è specificato nel modo giusto e l'utente dovrà rendersi conto che qualcosa non va.


1
Perché stai mescolando idiomi qui? Si utilizza la notazione URI corretta nel primo paragrafo e quindi si passa ai parametri di query? L'uso dei parametri di query per ottenere una risorsa con un ID di 123 è completamente fuori base qui.
Andrew T Finnell,

È stato chiaramente un errore. Ho aggiornato la mia risposta ora. Grazie per averlo notato.
pberggreen

Dopo essere stato nuovamente votato, ho esaminato ciò che ho scritto e mi sono reso conto che il post originale era corretto. Il mio punto era esattamente che se l'utente fa la cosa sbagliata, l'uso del plurale + singolare darà di fatto un messaggio di errore migliore rispetto all'uso del plurale.
pberggreen,

Sento ancora che ciò sta confondendo il problema in questione. L'idea di utilizzare il plurale è che si tratta di una raccolta. E il numero alla fine è un indice nella raccolta. Che cosa succede se OTTIENI / risorsa da solo? L'uso sia del plurale che del singolare insieme è abbastanza confuso. Dicendo / resources / 123 dice: Prendi la mia risorsa 123 nel bucket delle risorse.
Andrew T Finnell,
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.