API RESTful: verbi HTTP con URL condivisi o specifici?

25

Durante la creazione di una API RESTful , dovrei usare i verbi HTTP sullo stesso URL (quando è possibile) o dovrei creare un URL specifico per azione?

Ad esempio:

GET     /items      # Read all items
GET     /items/:id  # Read one item
POST    /items      # Create a new item
PUT     /items/:id  # Update one item
DELETE  /items/:id  # Delete one item

O con URL specifici come:

GET     /items            # Read all items
GET     /item/:id         # Read one item
POST    /items/new        # Create a new item
PUT     /item/edit/:id    # Update one item
DELETE  /item/delete/:id  # Delete one item
    
posta 53777A 15.11.2014 - 21:50
fonte

3 risposte

46

Nel tuo ultimo schema, mantieni i verbi negli URL delle tue risorse. Questo dovrebbe essere evitato in quanto i verbi HTTP dovrebbero essere usati a tale scopo. Abbraccia il protocollo sottostante invece di ignorarlo, duplicarlo o sovrascriverlo.

Guarda solo DELETE /item/delete/:id , inserisci le stesse informazioni due volte nella stessa richiesta. Questo è superfluo e dovrebbe essere evitato. Personalmente, sarei confuso con questo. L'API supporta effettivamente le richieste di DELETE ? Cosa succede se inserisco delete nell'URL e utilizzi invece un verbo HTTP diverso? Corrisponderà a qualcosa? Se sì, quale sarà scelto? Come cliente di un'API progettata correttamente, non dovrei dover fare queste domande.

Forse ne hai bisogno per supportare in qualche modo i client che non possono rilasciare DELETE o PUT richieste. In questo caso, passerei queste informazioni in un'intestazione HTTP. Alcune API usano un'intestazione X-HTTP-Method-Override per questo scopo specifico (che a mio avviso è abbastanza brutto comunque). Certamente non metterei i verbi nei percorsi però.

Vai per

GET     /items      # Read all items
GET     /items/:id  # Read one item
POST    /items      # Create a new item
PUT     /items/:id  # Update one item
DELETE  /items/:id  # Delete one item

Ciò che è importante dei verbi è che sono già ben definiti nelle specifiche HTTP e restare in linea con queste regole ti consente di usare cache, proxy e possibilmente altri strumenti esterni alla tua applicazione che capiscono la semantica di HTTP ma non la semantica della tua applicazione. Si noti che il motivo per cui si dovrebbe evitare di averli nei propri URL non riguarda le API RESTful che richiedono URL leggibili. Si tratta di evitare inutili ambiguità.

Inoltre, un'API RESTful può mappare questi verbi (o qualsiasi loro sottoinsieme) a qualsiasi insieme di semantica delle applicazioni, purché non vada contro le specifiche HTTP. Ad esempio, è perfettamente possibile creare un'API RESTful che utilizza le richieste GET solo se tutte le operazioni consentite sono entrambi sicuri e idempotenti . La mappatura di cui sopra è solo un esempio che si adatta al tuo caso di utilizzo ed è conforme alle specifiche. Non deve necessariamente essere così.

Per favore, tieni presente che un'API veramente RESTful non dovrebbe mai richiedere a un programmatore di leggere la documentazione estesa degli URL disponibili, purché sia conforme al principio HATEOAS (Hypertext as the Engine of Application), che è una delle principali ipotesi di REST . I collegamenti possono essere completamente incomprensibili per gli umani a patto che l'applicazione client sia in grado di comprenderli e utilizzarli per capire le possibili transizioni dello stato dell'applicazione.

    
risposta data 15.11.2014 - 22:12
fonte
14

Il primo.

Un URI / URL è un identificatore di risorsa (suggerimento nel nome: identificativo di risorsa uniforme). Con la prima convenzione, la risorsa di cui si parla quando si esegue "GET / user / 123" e la risorsa di cui si parla quando si esegue "DELETE / user / 123" è chiaramente la stessa risorsa perché hanno lo stesso URL.

Con la seconda convenzione, non puoi essere certo che "GET / user / 123" e "DELETE / user / delete / 123" siano effettivamente la stessa risorsa, e sembra implicare che stai eliminando una risorsa correlata rispetto alla risorsa stessa, quindi sarebbe piuttosto sorprendente che l'eliminazione di /user/delete/123 cancelli effettivamente /user/123 . Se tutte le operazioni funzionano su URL diversi, l'URI non funziona più come identificatore di risorsa.

Quando dici DELETE /user/123 , stai dicendo "cancella" record utente con ID 123 "". Mentre se si dice DELETE /user/delete/123 , quello che sembra implicare è "cancellare" il record deletor dell'utente con id 123 "", che probabilmente non è quello che si vuole dire. E anche se usi il verbo più corretto in questa situazione: "POST / user / delete / 123" che dice "fai l'operazione collegata a" user deletor con id 123 "", è ancora un modo indiretto per dire eliminare un record (questo è simile alla denominazione di un verbo in inglese).

Un modo in cui puoi pensare all'URL è trattarlo come un puntatore di oggetti e risorse come oggetti nella programmazione orientata agli oggetti. Quando fai GET /user/123 , DELETE /user/123 , puoi pensare a considerarli come metodi nell'oggetto: [/user/123].get() , [/user/123].delete() dove [] è come un operatore di dereferencing del puntatore ma per URL (se conosci una lingua che hanno dei puntatori). Uno dei principi di base di REST è un'interfaccia uniforme, cioè avere un insieme limitato di verbi / metodi che funziona per tutto in una vasta rete di risorse / oggetti.

Pertanto, il primo è migliore.

PS: ovviamente, questo sta guardando REST nel modo più puro. A volte la praticità batte la purezza e devi fare concessioni per clienti o strutture cerebrali che rendono difficile fare il REST corretto.

    
risposta data 16.11.2014 - 03:49
fonte
6

(scusa, la prima volta che ho perso mi sono perso / edit / e / delete / in (2) ...)

L'idea dell'URI è che è un identificatore di una risorsa indirizzabile , piuttosto che un metodo di chiamata . Quindi l'URI dovrebbe puntare a una risorsa specifica. E se si deferenza l'URI, si dovrebbe sempre ottenere la stessa risorsa.

Cioè, dovresti pensare agli URI nello stesso modo in cui pensi alla chiave primaria di una riga in un database. Identifica in modo univoco qualcosa: Universal Resource Identifier.

Quindi, se usi il plurale o il singolare, l'URI dovrebbe essere un identificatore piuttosto che un richiamo . Quello che stai provando a fare va nel metodo, ovvero: GET (ottieni), PUT (crea / aggiorna), CANCELLA (elimina) o POST (tutto il resto).

Quindi "/ item / delete / 123" interrompe REST perché non punta a una risorsa, è più un richiamo di metodo.

(Inoltre, solo semanticamente, dovresti essere in grado di OTTENERE un URI, decidere che è obsoleto, e quindi CANCELLARE lo stesso URI - perché è un identificatore. avere "/ delete /" e DELETE fa, quindi va contro la semantica HTTP. Stai trasmettendo 2 o più URI per risorsa dove 1 farà.)

Ora, il trucco è questo: non esiste una definizione chiara e chiara di ciò che è e non è una risorsa, quindi l'espediente comune in REST è definire un "nome di elaborazione" e puntare l'URI su quello. È praticamente un gioco di parole, ma soddisfa la semantica.

Quindi se, ad esempio, non potresti davvero usarlo per qualche motivo:

DELETE /items/123

potresti dichiarare al mondo che hai una risorsa di elaborazione "deletor" e utilizzare

POST /items/deletor  { id: 123 }

Ora sembra molto simile a RPC (Remote Procedure Call), ma cade attraverso la vasta scappatoia della clausola "elaborazione dati" della specifica POST indicata nelle specifiche HTTP.

Tuttavia, farlo è un po 'eccezionale, e se puoi usare il PUT comune per creare / aggiornare, DELETE per eliminare e POST per aggiungere, creare e tutto il resto, allora < em> dovrebbe , perché è un uso più standard di HTTP. Ma se hai un caso complicato come "commit" o "publish" o "redact", allora il caso di usare un nome di processore soddisfa i puristi di REST e ti dà ancora la semantica di cui hai bisogno.

    
risposta data 16.11.2014 - 04:40
fonte

Leggi altre domande sui tag