Comprensione di REST: verbi, codici di errore e autenticazione


602

Sto cercando un modo per avvolgere le API attorno alle funzioni predefinite nelle mie applicazioni Web, database e CMS basati su PHP.

Mi sono guardato intorno e ho trovato diversi quadri "scheletro". Oltre alle risposte alla mia domanda, c'è Tonic , un framework REST che mi piace perché è molto leggero.

Mi piace REST il meglio per la sua semplicità e vorrei creare un'architettura API basata su di essa. Sto cercando di capire meglio i principi di base e non l'ho ancora capito del tutto. Pertanto, una serie di domande.

1. Lo capisco bene?

Dire che ho una risorsa "utenti". Potrei impostare un numero di URI in questo modo:

/api/users     when called with GET, lists users
/api/users     when called with POST, creates user record
/api/users/1   when called with GET, shows user record
               when called with PUT, updates user record
               when called with DELETE, deletes user record

è questa una corretta rappresentazione di un'architettura RESTful finora?

2. Ho bisogno di più verbi

Creare, aggiornare ed eliminare potrebbe essere sufficiente in teoria, ma in pratica avrò bisogno di molti più verbi. Mi rendo conto che queste sono cose che potrebbero essere incorporate in una richiesta di aggiornamento, ma sono azioni specifiche che possono avere codici di ritorno specifici e non vorrei buttarle tutte in una sola azione.

Alcuni che vengono in mente nell'esempio dell'utente sono:

activate_login
deactivate_login
change_password
add_credit

come potrei esprimere azioni come quelle in un'architettura URL RESTful?

Il mio istinto sarebbe quello di fare una chiamata GET a un URL come

/api/users/1/activate_login 

e aspettarsi un codice di stato indietro.

Ciò si discosta dall'idea di usare i verbi HTTP. Cosa ne pensi?

3. Come restituire messaggi e codici di errore

Gran parte della bellezza di REST deriva dall'uso di metodi HTTP standard. In caso di errore, emetto un'intestazione con un codice di stato di errore 3xx, 4xx o 5xx. Per una descrizione dettagliata dell'errore, posso usare il corpo (giusto?). Fin qui tutto bene. Ma quale sarebbe il modo di trasmettere un codice di errore proprietario che è più dettagliato nel descrivere ciò che è andato storto (ad es. "Impossibile connettersi al database" o "accesso al database errato")? Se lo inserisco nel corpo insieme al messaggio, devo analizzarlo in seguito. Esiste un'intestazione standard per questo tipo di cose?

4. Come eseguire l'autenticazione

  • Come sarebbe un'autenticazione basata su chiave API secondo i principi REST?
  • Ci sono punti di forza contro l'utilizzo delle sessioni durante l'autenticazione di un client REST, a parte il fatto che si tratta di una palese violazione del principio REST? :) (sto scherzando solo per metà, l'autenticazione basata su sessione giocherebbe bene con la mia infrastruttura esistente.)

13
@Daniel, grazie per la modifica. "I more verbs" era un gioco di parole intenzionale, ma lo sto lasciando così com'è, ora è più facile da leggere. :)
Pekka,

1
A proposito, sulla descrizione dell'errore. Ho finito per mettere la descrizione dell'errore nell'intestazione della risposta. Aggiungi solo l'intestazione denominata "Descrizione errore".
Andrii Muzychuk,

Sembra più una domanda di sicurezza dell'applicazione. La sicurezza delle applicazioni non riguarda REST.
Nazar Merza,

@NazarMerza come sono le domande di sicurezza delle applicazioni 1., 2. e 3.?
Pekka,

Risposte:


621

Ho notato questa domanda con un paio di giorni di ritardo, ma sento di poter aggiungere qualche informazione. Spero che questo possa essere utile per la tua impresa RESTful.


Punto 1: lo sto capendo bene?

Hai capito bene. Questa è una rappresentazione corretta di un'architettura RESTful. Puoi trovare la seguente matrice di Wikipedia molto utile per definire i tuoi nomi e verbi:


Quando si ha a che fare con un URI Collection come:http://example.com/resources/

  • OTTIENI : elenca i membri della raccolta, completi degli URI dei membri per ulteriore navigazione. Ad esempio, elenca tutte le auto in vendita.

  • PUT : significato definito come "sostituisci l'intera raccolta con un'altra raccolta".

  • POST : creare una nuova voce nella raccolta in cui l'ID è assegnato automaticamente dalla raccolta. L'ID creato viene generalmente incluso come parte dei dati restituiti da questa operazione.

  • ELIMINA : significato definito come "elimina l'intera raccolta".


Quando si ha a che fare con un URI membro come:http://example.com/resources/7HOU57Y

  • OTTIENI : recupera una rappresentazione del membro indirizzato della raccolta espressa in un tipo MIME appropriato.

  • PUT : aggiorna il membro indirizzato della raccolta o crealo con l'ID specificato.

  • POST : considera il membro indirizzato come una raccolta a sé stante e ne crea un nuovo subordinato.

  • ELIMINA : elimina il membro indirizzato della raccolta.


Punto 2: ho bisogno di più verbi

In generale, quando pensi di aver bisogno di più verbi, ciò può effettivamente significare che le tue risorse devono essere identificate di nuovo. Ricorda che in REST agisci sempre su una risorsa o su una raccolta di risorse. Quello che scegli come risorsa è abbastanza importante per la tua definizione API.

Attiva / Disattiva Accesso : Se si sta creando una nuova sessione, allora si può prendere in considerazione "la sessione" come la risorsa. Per creare una nuova sessione, utilizzare POST per http://example.com/sessions/con le credenziali nel corpo. Per scadere esso uso PUT o DELETE (forse a seconda se si intende mantenere una cronologia della sessione) a http://example.com/sessions/SESSION_ID.

Cambia password: questa volta la risorsa è "l'utente". Avresti bisogno di un PUT http://example.com/users/USER_IDcon le vecchie e nuove password nel corpo. Stai agendo sulla risorsa "l'utente" e una password di modifica è semplicemente una richiesta di aggiornamento. È abbastanza simile all'istruzione UPDATE in un database relazionale.

Il mio istinto sarebbe quello di fare una chiamata GET a un URL come /api/users/1/activate_login

Ciò è in contrasto con un principio REST fondamentale: l'uso corretto dei verbi HTTP. Qualsiasi richiesta GET non dovrebbe mai lasciare alcun effetto collaterale.

Ad esempio, una richiesta GET non dovrebbe mai creare una sessione sul database, restituire un cookie con un nuovo ID sessione o lasciare residui sul server. Il verbo GET è come l'istruzione SELECT in un motore di database. Ricorda che la risposta a qualsiasi richiesta con il verbo GET dovrebbe essere in grado di cache quando richiesto con gli stessi parametri, proprio come quando si richiede una pagina Web statica.


Punto 3: come restituire messaggi e codici di errore

Considera i codici di stato HTTP 4xx o 5xx come categorie di errori. Puoi elaborare l'errore nel corpo.

Impossibile connettersi al database: / Accesso al database errato : in genere è necessario utilizzare un errore 500 per questi tipi di errori. Questo è un errore sul lato server. Il cliente non ha fatto nulla di male. 500 errori sono normalmente considerati "riprovabili". cioè il client può ritentare la stessa richiesta esatta e aspettarsi che abbia successo una volta risolti i problemi del server. Specifica i dettagli nel corpo, in modo che il cliente sarà in grado di fornire un contesto a noi umani.

L'altra categoria di errori sarebbe la famiglia 4xx, che in generale indica che il client ha fatto qualcosa di sbagliato. In particolare, questa categoria di errori indica normalmente al client che non è necessario ripetere la richiesta così com'è, poiché continuerà a fallire in modo permanente. cioè il client deve cambiare qualcosa prima di ritentare questa richiesta. Ad esempio, gli errori "Risorsa non trovata" (HTTP 404) o "Richiesta non valida" (HTTP 400) rientrerebbero in questa categoria.


Punto 4: Come eseguire l'autenticazione

Come sottolineato al punto 1, invece di autenticare un utente, potresti voler pensare alla creazione di una sessione. Verrà restituito un nuovo "ID sessione", insieme al codice di stato HTTP appropriato (200: accesso concesso o 403: accesso negato).

Ti verrà quindi chiesto al tuo server RESTful: "Puoi ottenere la risorsa per questo ID sessione?".

Non esiste una modalità autenticata: REST è senza stato: si crea una sessione, si chiede al server di fornire risorse utilizzando questo ID sessione come parametro e al logout si annulla o scade la sessione.


6
Molto buono, tuttavia l'utilizzo di PUTper modificare una password è probabilmente errato; PUTrichiede l'intera risorsa, quindi dovresti inviare tutti gli attributi utente per conformarti a HTTP (e quindi con HATEOAS REST). Piuttosto, per cambiare semplicemente la password si dovrebbe usare PATCHo POST.
Lawrence Dol

1
Penso che questo post sarebbe perfetto se ti espandessi di più su ciò che "POST: tratta il membro indirizzato come una raccolta a sé stante e ne crea un nuovo subordinato". si intende. - Ho trovato cosa significa Googling - è un'eccezione alla tua risposta altrimenti eccezionale.
Martin Konecny,

6
Non sono d'accordo con l'ultima frase. Stai spiegando come REST sia apolide. Il login per creare una sessione, quindi il logout per terminare la sessione dopo aver fatto qualche lavoro è il miglior esempio di API stateful.
Brandon,

1
"Questo va contro un principio REST fondamentale: l'uso corretto dei verbi HTTP. Qualsiasi richiesta GET non dovrebbe mai lasciare alcun effetto collaterale." - Cosa succede se si desidera mantenere un numero di visite per la risorsa?
bobbyalex,

1
Questo articolo dovrebbe rispondere alle tue domande. saipraveenblog.wordpress.com/2014/09/09/9/rest-api-best-practices
java_geek

79

In poche parole, lo stai facendo completamente all'indietro.

Non dovresti avvicinarti a questo da quali URL dovresti usare. Gli URL verranno effettivamente "gratis" una volta che avrai deciso quali risorse sono necessarie per il tuo sistema E come rappresenterai quelle risorse e le interazioni tra le risorse e lo stato dell'applicazione.

Per citare Roy Fielding

Un'API REST dovrebbe impiegare quasi tutto il suo sforzo descrittivo per definire i tipi di media utilizzati per rappresentare le risorse e guidare lo stato dell'applicazione, o per definire nomi di relazioni estese e / o mark-up abilitato per ipertesti per tipi di media standard esistenti. Qualsiasi sforzo speso per descrivere quali metodi utilizzare su quali URI di interesse dovrebbero essere interamente definiti nell'ambito delle regole di elaborazione per un tipo di supporto (e, nella maggior parte dei casi, già definito da tipi di supporto esistenti). [Il fallimento qui implica che le informazioni fuori banda guidano l'interazione anziché l'ipertesto.]

Le persone iniziano sempre con gli URI e pensano che questa sia la soluzione, e quindi tendono a perdere un concetto chiave nell'architettura REST, in particolare, come citato sopra, "Il fallimento qui implica che l'informazione fuori banda sta guidando l'interazione anziché l'ipertesto. "

Ad essere onesti, molti vedono un sacco di URI e alcuni GET e PUT e POST e pensano che REST sia facile. REST non è facile. RPC su HTTP è facile, spostare BLOB di dati avanti e indietro inviati tramite payload HTTP è facile. REST, tuttavia, va oltre. REST è il protocollo agnostico. HTTP è solo molto popolare e adatto ai sistemi REST.

REST vive nei tipi di media, nelle loro definizioni e nel modo in cui l'applicazione guida le azioni disponibili per tali risorse tramite ipertesto (collegamenti, in modo efficace).

Esistono diversi punti di vista sui tipi di media nei sistemi REST. Alcuni favoriscono payload specifici dell'applicazione, mentre altri preferiscono elevare i tipi di media esistenti a ruoli appropriati per l'applicazione. Ad esempio, da un lato hai schemi XML specifici progettati per la tua applicazione rispetto all'uso di qualcosa come XHTML come tua rappresentazione, forse attraverso microformati e altri meccanismi.

Entrambi gli approcci hanno il loro posto, penso, l'XHTML funziona molto bene in scenari che si sovrappongono sia al web guidato dall'uomo che al computer, mentre i primi, tipi di dati più specifici che ritengo possano facilitare le interazioni macchina-macchina. Trovo che il potenziamento dei formati delle materie prime possa rendere potenzialmente difficile la negoziazione dei contenuti. "application / xml + yourresource" è molto più specifico come tipo di media rispetto a "application / xhtml + xml", poiché quest'ultimo può applicarsi a molti payload che potrebbero essere o meno qualcosa a cui un client del computer è effettivamente interessato, né può determinare senza introspezione.

Tuttavia, XHTML funziona molto bene (ovviamente) nella rete umana in cui i browser Web e il rendering sono molto importanti.

La tua candidatura ti guiderà in questo tipo di decisioni.

Parte del processo di progettazione di un sistema REST è scoprire le risorse di prima classe nel sistema, insieme alla derivata, risorse di supporto necessarie per supportare le operazioni sulle risorse primarie. Una volta scoperte le risorse, quindi la rappresentazione di tali risorse, nonché i diagrammi di stato che mostrano il flusso di risorse tramite ipertesto all'interno delle rappresentazioni perché la sfida successiva.

Ricordiamo che ogni rappresentazione di una risorsa, in un sistema ipertestuale, combina sia la rappresentazione effettiva della risorsa che le transizioni di stato disponibili per la risorsa. Considera ogni risorsa un nodo in un grafico, con i collegamenti che sono le linee che lasciano quel nodo ad altri stati. Questi collegamenti informano i clienti non solo su ciò che può essere fatto, ma anche su ciò che è necessario per farlo (poiché un buon collegamento combina l'URI e il tipo di supporto richiesto).

Ad esempio, potresti avere:

<link href="http://example.com/users" rel="users" type="application/xml+usercollection"/>
<link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>

La documentazione parlerà del campo rel chiamato "utenti" e del tipo di supporto di "application / xml + youruser".

Questi collegamenti possono sembrare ridondanti, parlano tutti allo stesso URI, praticamente. Ma non lo sono.

Questo perché per la relazione "utenti", quel collegamento parla della raccolta di utenti e puoi usare l'interfaccia uniforme per lavorare con la raccolta (OTTIENI per recuperarli tutti, ELIMINA per eliminarli tutti, ecc.)

Se pubblichi questo URL, dovrai passare un documento "application / xml + usercollection", che probabilmente conterrà solo una singola istanza utente all'interno del documento in modo da poter aggiungere l'utente o no, forse, per aggiungerne altri in una volta. Forse la tua documentazione suggerirà che puoi semplicemente passare un singolo tipo di utente, anziché la raccolta.

Puoi vedere cosa richiede l'applicazione per eseguire una ricerca, come definito dal link "cerca" e dal suo mediatype. La documentazione per il tipo di supporto di ricerca ti dirà come si comporta e cosa aspettarsi come risultati.

Il takeaway qui, però, è che gli URI stessi sono sostanzialmente irrilevanti. L'applicazione controlla gli URI, non i client. Oltre ad alcuni "punti di accesso", i tuoi clienti dovrebbero fare affidamento sugli URI forniti dall'applicazione per il suo lavoro.

Il cliente deve sapere come manipolare e interpretare i tipi di media, ma non deve preoccuparsi di dove va.

Questi due collegamenti sono semanticamente identici agli occhi di un cliente:

<link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>
<link href="http://example.com/AW163FH87SGV" rel="search" type="application/xml+usersearchcriteria"/>

Quindi, concentrati sulle tue risorse. Concentrati sulle loro transizioni di stato nell'applicazione e su come ottenere i risultati migliori.


1
Grazie Will per questa risposta molto profonda. Diversi punti presi. Mi rendo conto che la pianificazione da "come appare l'URL" lo sta facendo al contrario, e sto pianificando anche dal punto di vista delle risorse. Avere URL con cui giocare mi semplifica la comprensione del concetto. È possibile che le mie esigenze possano essere soddisfatte con un sistema che non segue al 100% i principi REST come definito qui. Elaborerò un elenco completo di requisiti per ciascun tipo di risorsa, credo che sarò in grado di decidere allora. Saluti.
Pekka,

30

Ri 1 : Finora sembra tutto a posto. Ricordare di restituire l'URI dell'utente appena creato in un'intestazione "Posizione:" come parte della risposta a POST, insieme a un codice di stato "201 creato".

re 2: L'attivazione tramite GET è una cattiva idea e includere il verbo nell'URI è un odore di progettazione. Potresti prendere in considerazione l'idea di restituire un modulo su un GET. In un'app Web, questo sarebbe un modulo HTML con un pulsante di invio; nel caso d'uso API, potresti voler restituire una rappresentazione che contiene un URI a PUT per attivare l'account. Ovviamente puoi includere questo URI anche nella risposta su POST a / utenti. L'utilizzo di PUT assicurerà che la tua richiesta sia idempotente, ovvero può essere tranquillamente inviata nuovamente se il client non è sicuro del successo. In generale, pensa a quali risorse puoi trasformare i tuoi verbi (una sorta di "denominazione dei verbi"). Chiediti con quale metodo la tua azione specifica è maggiormente allineata. Ad esempio change_password -> PUT; disattivare -> probabilmente ELIMINA; add_credit -> possibilmente POST o PUT.

re 3. Non inventare nuovi codici di stato, a meno che tu non creda che siano così generici da meritare di essere standardizzati a livello globale. Cerca di utilizzare il codice di stato più appropriato disponibile (leggi tutti in RFC 2616). Includi ulteriori informazioni nel corpo della risposta. Se sei davvero sicuro di voler inventare un nuovo codice di stato, ripensaci; se ancora ci credi, assicurati di scegliere almeno la categoria giusta (1xx -> OK, 2xx -> informativo, 3xx -> reindirizzamento; 4xx-> errore client, 5xx -> errore server). Ho già detto che inventare nuovi codici di stato è una cattiva idea?

re 4. Se possibile, utilizzare il framework di autenticazione incorporato in HTTP. Scopri come Google esegue l'autenticazione in GData. In generale, non inserire le chiavi API negli URI. Cerca di evitare sessioni per migliorare la scalabilità e supportare la memorizzazione nella cache: se la risposta a una richiesta differisce a causa di qualcosa che è accaduto in precedenza, di solito ti sei legato a un'istanza specifica del processo del server. È molto meglio trasformare lo stato della sessione in uno stato client (ad es. Renderlo parte delle richieste successive) o renderlo esplicito trasformandolo in stato (server) delle risorse, ovvero assegnandogli il proprio URI.


Puoi discutere perché non inserire le chiavi API negli URL? È perché sono visibili nei registri proxy? Cosa succede se le chiavi sono temporanee, basate sul tempo? Cosa succede se si utilizza HTTPS?
MikeSchinkel,

4
Oltre a violare lo spirito (gli URI dovrebbero identificare le cose), la conseguenza principale è che rovina la cache.
Stefan Tilkov,

22

1. Hai l'idea giusta su come progettare le tue risorse, IMHO. Non cambierei nulla.

2. Invece di provare a estendere HTTP con più verbi, considera a cosa i tuoi verbi proposti possono essere ridotti in termini di metodi e risorse HTTP di base. Ad esempio, invece di un activate_loginverbo, è possibile impostare risorse come: /api/users/1/login/activeche è un semplice booleano. Per attivare un accesso, basta PUTun documento lì che dice 'vero' o 1 o altro. Per disattivare, PUTun documento lì che è vuoto o dice 0 o falso.

Allo stesso modo, per modificare o impostare le password, basta fare PUTs /api/users/1/password.

Ogni volta che è necessario aggiungere qualcosa (come un credito), pensare in termini di POSTs. Ad esempio, potresti fare un POSTa una risorsa come /api/users/1/creditscon un corpo contenente il numero di crediti da aggiungere. A PUTsulla stessa risorsa potrebbe essere utilizzato per sovrascrivere il valore piuttosto che aggiungere. A POSTcon un numero negativo nel corpo verrebbe sottratto, e così via.

3. Consiglio vivamente di non estendere i codici di stato HTTP di base. Se non riesci a trovarne uno che corrisponda esattamente alla tua situazione, scegli quello più vicino e inserisci i dettagli dell'errore nel corpo della risposta. Inoltre, ricorda che le intestazioni HTTP sono estensibili; l'applicazione può definire tutte le intestazioni personalizzate che ti piacciono. Un'applicazione su cui ho lavorato, ad esempio, potrebbe restituire una 404 Not Foundin più circostanze. Anziché fare in modo che il client analizzi il corpo della risposta per il motivo, abbiamo appena aggiunto una nuova intestazione X-Status-Extended, che conteneva le nostre estensioni di codice di stato proprietarie. Quindi potresti vedere una risposta come:

HTTP/1.1 404 Not Found    
X-Status-Extended: 404.3 More Specific Error Here

In questo modo un client HTTP come un browser Web saprà ancora cosa fare con il normale codice 404 e un client HTTP più sofisticato può scegliere di guardare l' X-Status-Extendedintestazione per informazioni più specifiche.

4. Per l'autenticazione, ti consiglio di usare l'autenticazione HTTP se puoi. Ma IMHO non ha nulla di sbagliato nell'utilizzare l'autenticazione basata su cookie se è più facile per te.


4
Buona idea di usare risorse "estese" per fare cose a porzioni più piccole di una risorsa più grande.
womble,

1
I cookie sono validi in HTTP / REST, ma il server non deve memorizzarli come stato (quindi non come sessione). Il cookie può memorizzare un valore come un HMAC, tuttavia, che può essere disassemblato senza cercare altrove lo stato.
Bruce Alderson,

14

Nozioni di base REST

REST ha un vincolo di interfaccia uniforme, che afferma che il client REST deve fare affidamento sugli standard anziché sui dettagli specifici dell'applicazione del servizio REST effettivo, in modo che il client REST non si rompa con piccole modifiche e sarà probabilmente riutilizzabile.

Quindi esiste un contratto tra il client REST e il servizio REST. Se si utilizza HTTP come protocollo sottostante, i seguenti standard fanno parte del contratto:

  • HTTP 1.1
    • definizioni del metodo
    • definizioni del codice di stato
    • intestazioni di controllo della cache
    • accetta e intestazioni del tipo di contenuto
    • intestazioni di autenticazione
  • IRI ( URI utf8 )
  • corpo (scegline uno)
    • tipo MIME specifico dell'applicazione registrato, ad esempio labirinto + xml
    • tipo MIME specifico del fornitore, ad esempio vnd.github + json
    • tipo MIME generico con
      • vocabolario RDF specifico dell'applicazione, ad esempio ld + json & hydra , schema.org
      • profilo specifico dell'applicazione, ad es. hal + json e param link profilo (immagino)
  • collegamenti ipertestuali
    • cosa dovrebbe contenerli (scegline uno)
    • semantica
      • utilizzare le relazioni di collegamento IANA e probabilmente relazioni di collegamento personalizzate
      • utilizzare un vocabolario RDF specifico per l'applicazione

REST ha un vincolo stateless, che dichiara che la comunicazione tra il servizio REST e il client deve essere stateless. Ciò significa che il servizio REST non può mantenere gli stati client, quindi non è possibile disporre di un archivio sessioni lato server. Devi autenticare ogni singola richiesta. Quindi, ad esempio, l'autenticazione di base HTTP (parte dello standard HTTP) va bene, perché invia nome utente e password con ogni richiesta.

Per rispondere alle tue domande

  1. Sì, può essere.

    Solo per citare, i clienti non si preoccupano della struttura IRI, si preoccupano della semantica, perché seguono collegamenti con relazioni di collegamento o attributi di dati collegati (RDF).

    L'unica cosa importante degli IRI è che un singolo IRI deve identificare solo una singola risorsa. È consentito a una singola risorsa, come un utente, avere molti IRI diversi.

    È abbastanza semplice il motivo per cui usiamo simpatici IRI /users/123/password; è molto più semplice scrivere la logica di routing sul server quando si capisce l'IRI semplicemente leggendolo.

  2. Hai più verbi, come PUT, PATCH, OPTIONS e anche di più, ma non ne hai bisogno più ... Invece di aggiungere nuovi verbi devi imparare come aggiungere nuove risorse.

    activate_login -> PUT /login/active true deactivate_login -> PUT /login/active false change_password -> PUT /user/xy/password "newpass" add_credit -> POST /credit/raise {details: {}}

    (L'accesso non ha senso dal punto di vista REST, a causa del vincolo stateless.)

  3. Ai tuoi utenti non interessa il motivo per cui esiste il problema. Vogliono sapere solo se c'è successo o errore e probabilmente un messaggio di errore che possono capire, ad esempio: "Siamo spiacenti, ma non siamo riusciti a salvare il tuo post.", Ecc ...

    Le intestazioni di stato HTTP sono le intestazioni standard. Tutto il resto dovrebbe essere nel corpo, penso. Una singola intestazione non è sufficiente per descrivere ad esempio messaggi di errore multilingue dettagliati.

  4. Il vincolo stateless (insieme alla cache e ai vincoli di sistema a più livelli) assicura che il servizio si ridimensiona bene. Sicuramente non vorrai mantenere milioni di sessioni sul server, quando puoi fare lo stesso sui client ...

    Il client di terze parti ottiene un token di accesso se l'utente concede l'accesso ad esso utilizzando il client principale. Successivamente il client di terze parti invia il token di accesso con ogni richiesta. Esistono soluzioni più complicate, ad esempio è possibile firmare ogni singola richiesta, ecc. Per ulteriori dettagli consultare il manuale di OAuth.

Letteratura correlata


11

Per gli esempi che hai dichiarato userei quanto segue:

activate_login

POST /users/1/activation

deactivate_login

DELETE /users/1/activation

cambia la password

PUT /passwords (questo presuppone che l'utente sia autenticato)

add_credit

POST /credits (questo presuppone che l'utente sia autenticato)

Per gli errori restituiresti l'errore nel corpo nel formato in cui hai ricevuto la richiesta, quindi se ricevi:

DELETE /users/1.xml

Restituiresti la risposta in XML, lo stesso sarebbe vero per JSON ecc ...

Per l'autenticazione è necessario utilizzare l'autenticazione http.


1
Non userei createcome parte dell'URI (ricorda che gli URI dovrebbero essere nomi e i metodi HTTP dovrebbero essere verbi che operano su quei nomi.) Invece, avrei una risorsa come quella /users/1/activeche può essere un semplice booleano, e può essere impostato inserendo 1 o 0 su quella risorsa.
friedo,

Hai ragione, ho eliminato / create. Dovrebbe essere solo un post per la risorsa singleton.
jonnii,

3
Non activationuserei neanche sull'URI, a meno che tu non manipoli e gestisca esplicitamente una risorsa con il nome di /users/1/activation. Cosa fa un GET su questo? Cosa fa un PUT? Mi sembra che tu stia pronunciando l'URI. Inoltre, per quanto riguarda la negoziazione del tipo di contenuto, spesso è meglio lasciarlo fuori dall'URI e inserirlo nelle intestazioni, come Accept.
Cheeso,

6
  1. Usa post quando non sai come apparirà il nuovo URI della risorsa (crei un nuovo utente, l'applicazione assegnerebbe al nuovo utente il suo ID), PUT per aggiornare o creare risorse che sai come saranno rappresentate (esempio : PUT /myfiles/thisismynewfile.txt)
  2. restituisce la descrizione dell'errore nel corpo del messaggio
  3. È possibile utilizzare l'autenticazione HTTP (se è sufficiente) i servizi Web devono essere stati

5

Suggerirei (come primo passaggio) che PUTdovrebbe essere utilizzato solo per l'aggiornamento di entità esistenti. POSTdovrebbe essere usato per crearne di nuovi. vale a dire

/api/users     when called with PUT, creates user record

non mi sento bene. Il resto della prima sezione (riutilizzo del verbo) sembra logico, tuttavia.


probabilmente qualcuno pensava che questa non fosse davvero una risposta alla sua domanda
lubos hasko,

6
La mia opinione su PUT contro POST per la creazione di nuove entità è quella di utilizzare PUT quando il chiamante controlla il nome della risorsa, in modo da poter passare alla risorsa esatta e POST quando la chiamata controlla il nome della nuova risorsa (come nell'esempio qui).
SteveD,

5

Verbo, ma copiato dalla specifica del metodo HTTP 1.1 su http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

9.3 OTTIENI

Il metodo GET significa recuperare qualsiasi informazione (sotto forma di entità) identificata dall'URI di richiesta. Se l'URI della richiesta fa riferimento a un processo di produzione di dati, sono i dati prodotti che devono essere restituiti come entità nella risposta e non il testo di origine del processo, a meno che tale testo non sia l'output del processo.

La semantica del metodo GET cambia in un "GET condizionale" se il messaggio di richiesta include un campo di intestazione If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match o If-Range. Un metodo GET condizionale richiede che l'entità venga trasferita solo nelle circostanze descritte dai campi dell'intestazione condizionale. Il metodo GET condizionale ha lo scopo di ridurre l'utilizzo della rete non necessario consentendo l'aggiornamento delle entità memorizzate nella cache senza richiedere più richieste o il trasferimento di dati già detenuti dal client.

La semantica del metodo GET cambia in "GET parziale" se il messaggio di richiesta include un campo di intestazione Range. Un GET parziale richiede che venga trasferita solo una parte dell'entità, come descritto nella sezione 14.35. Il metodo GET parziale ha lo scopo di ridurre l'utilizzo della rete non necessario consentendo il completamento di entità parzialmente recuperate senza trasferire i dati già detenuti dal client.

La risposta a una richiesta GET è memorizzabile nella cache se e solo se soddisfa i requisiti per la memorizzazione nella cache HTTP descritti nella sezione 13.

Vedere la sezione 15.1.3 per considerazioni sulla sicurezza quando utilizzato per i moduli.

9.5 POST

Il metodo POST viene utilizzato per richiedere che il server di origine accetti l'entità racchiusa nella richiesta come nuovo subordinato della risorsa identificata dall'URI di richiesta nella riga di richiesta. POST è progettato per consentire un metodo uniforme per coprire le seguenti funzioni:

  - Annotation of existing resources;
  - Posting a message to a bulletin board, newsgroup, mailing list,
    or similar group of articles;
  - Providing a block of data, such as the result of submitting a
    form, to a data-handling process;
  - Extending a database through an append operation.

La funzione effettiva eseguita dal metodo POST è determinata dal server e di solito dipende dall'URI di richiesta. L'entità pubblicata è subordinata a tale URI allo stesso modo in cui un file è subordinato a una directory che lo contiene, un articolo di notizie è subordinato a un newsgroup in cui è pubblicato o un record è subordinato a un database.

L'azione eseguita dal metodo POST potrebbe non comportare una risorsa che può essere identificata da un URI. In questo caso, 200 (OK) o 204 (Nessun contenuto) è lo stato di risposta appropriato, a seconda che la risposta includa o meno un'entità che descrive il risultato.

Se una risorsa è stata creata sul server di origine, la risposta DOVREBBE essere 201 (Creata) e contenere un'entità che descriva lo stato della richiesta e si riferisca alla nuova risorsa e un'intestazione Ubicazione (vedere la sezione 14.30).

Le risposte a questo metodo non sono memorizzabili nella cache, a meno che la risposta non includa i campi di intestazione Controllo cache o Scadenza appropriati. Tuttavia, la risposta 303 (Vedi altro) può essere utilizzata per indirizzare l'agente utente a recuperare una risorsa memorizzabile nella cache.

Le richieste POST DEVONO rispettare i requisiti di trasmissione dei messaggi di cui alla sezione 8.2.

Vedere la sezione 15.1.3 per considerazioni sulla sicurezza.

9.6 PUT

Il metodo PUT richiede che l'entità inclusa sia archiviata nell'URI di richiesta fornito. Se l'URI della richiesta fa riferimento a una risorsa già esistente, l'entità inclusa DOVREBBE essere considerata come una versione modificata di quella residente sul server di origine. Se l'URI di richiesta non punta a una risorsa esistente e tale URI può essere definito come una nuova risorsa dall'agente utente richiedente, il server di origine può creare la risorsa con tale URI. Se viene creata una nuova risorsa, il server di origine DEVE informare l'agente utente tramite la risposta 201 (creata). Se una risorsa esistente viene modificata, i codici di risposta 200 (OK) o 204 (Nessun contenuto) DOVREBBERO essere inviati per indicare il completamento con successo della richiesta. Se la risorsa non può essere creata o modificata con l'URI di richiesta, dovrebbe essere fornita un'opportuna risposta all'errore che rifletta la natura del problema. Il destinatario dell'entità NON DEVE ignorare nessuna intestazione Content- * (es. Content-Range) che non comprende o implementa e DEVE restituire una risposta 501 (non implementata) in tali casi.

Se la richiesta passa attraverso una cache e l'URI della richiesta identifica una o più entità attualmente memorizzate nella cache, tali voci DOVREBBERO essere trattate come obsolete. Le risposte a questo metodo non sono memorizzabili nella cache.

La differenza fondamentale tra le richieste POST e PUT si riflette nel diverso significato dell'URI di richiesta. L'URI in una richiesta POST identifica la risorsa che gestirà l'entità chiusa. Tale risorsa potrebbe essere un processo di accettazione dei dati, un gateway verso qualche altro protocollo o un'entità separata che accetta le annotazioni. Al contrario, l'URI in una richiesta PUT identifica l'entità racchiusa nella richiesta: l'agente utente sa cosa è destinato l'URI e il server NON DEVE tentare di applicare la richiesta ad altre risorse. Se il server desidera che la richiesta venga applicata a un URI diverso,

DEVE inviare una risposta 301 (spostata in modo permanente); l'agente dell'utente PUO 'quindi prendere la propria decisione riguardo al reindirizzamento della richiesta.

Una singola risorsa può essere identificata da molti URI diversi. Ad esempio, un articolo potrebbe avere un URI per identificare "la versione corrente" che è separata dall'URI che identifica ciascuna versione particolare. In questo caso, una richiesta PUT su un URI generale potrebbe comportare la definizione di diversi altri URI dal server di origine.

HTTP / 1.1 non definisce in che modo un metodo PUT influisce sullo stato di un server di origine.

Le richieste PUT DEVONO rispettare i requisiti di trasmissione dei messaggi di cui alla sezione 8.2.

Salvo diversamente specificato per una particolare intestazione di entità, le intestazioni di entità nella richiesta PUT DOVREBBERO essere applicate alla risorsa creata o modificata dal PUT.

9.7 ELIMINA

Il metodo DELETE richiede che il server di origine elimini la risorsa identificata dall'URI di richiesta. Questo metodo può essere ignorato dall'intervento umano (o altri mezzi) sul server di origine. Non è possibile garantire al client che l'operazione sia stata eseguita, anche se il codice di stato restituito dal server di origine indica che l'azione è stata completata correttamente. Tuttavia, il server NON DOVREBBE indicare successo a meno che, al momento della risposta, non intenda eliminare la risorsa o spostarla in una posizione inaccessibile.

Una risposta corretta DOVREBBE essere 200 (OK) se la risposta include un'entità che descrive lo stato, 202 (Accettato) se l'azione non è stata ancora attuata o 204 (Nessun contenuto) se l'azione è stata attuata ma la risposta non include un'entità.

Se la richiesta passa attraverso una cache e l'URI della richiesta identifica una o più entità attualmente memorizzate nella cache, tali voci DOVREBBERO essere trattate come obsolete. Le risposte a questo metodo non sono memorizzabili nella cache.


2

Informazioni sui codici di ritorno REST: è errato mescolare codici protocollo HTTP e risultati REST.

Tuttavia, ho visto molte implementazioni mescolarle e molti sviluppatori potrebbero non essere d'accordo con me.

I codici di ritorno HTTP sono correlati a HTTP Requestse stesso. Una chiamata REST viene eseguita utilizzando una richiesta del protocollo di trasferimento Hypertext e funziona a un livello inferiore rispetto al metodo REST richiamato stesso. REST è un concetto / approccio e il suo output è un risultato aziendale / logico , mentre il codice risultato HTTP è un trasporto .

Ad esempio, restituendo "404 Non trovato" quando si chiama / users / è confuso, perché può significare:

  • URI errato (HTTP)
  • Nessun utente trovato (REST)

"403 Proibito / Accesso negato" può significare:

  • È richiesta un'autorizzazione speciale. I browser possono gestirlo chiedendo l'utente / password. (HTTP)
  • Autorizzazioni di accesso errate configurate sul server. (HTTP)
  • Devi essere autenticato (REST)

E l'elenco potrebbe continuare con "Errore del server 500" (un errore HTTP generato da Apache / Nginx o un errore di vincolo aziendale in REST) ​​o altri errori HTTP ecc ...

Dal codice, è difficile capire quale fosse la ragione dell'errore, un errore HTTP (trasporto) o un errore REST (logico).

Se la richiesta HTTP è stata eseguita correttamente, dovrebbe sempre restituire 200 codice, indipendentemente dal record trovato o meno. Perché la risorsa URI è stata trovata ed è stata gestita dal server http. Sì, potrebbe restituire un set vuoto. È possibile ricevere una pagina Web vuota con 200 come risultato http, giusto?

Invece di questo è possibile restituire 200 codice HTTP e semplicemente un JSON con un array / oggetto vuoto, oppure utilizzare un flag bool risultato / successo per informare sullo stato dell'operazione eseguita.

Inoltre, alcuni provider di servizi Internet potrebbero intercettare le tue richieste e restituirti un codice HTTP 404. Ciò non significa che i tuoi dati non vengano trovati, ma è qualcosa di sbagliato a livello di trasporto.

Da Wiki :

Nel luglio 2004, il fornitore di telecomunicazioni britannico BT Group ha implementato il sistema di blocco dei contenuti Cleanfeed, che restituisce un errore 404 a qualsiasi richiesta di contenuto identificata come potenzialmente illegale da Internet Watch Foundation. Altri ISP restituiscono un errore HTTP 403 "proibito" nelle stesse circostanze. La pratica di impiegare falsi errori 404 come mezzo per nascondere la censura è stata segnalata anche in Tailandia e Tunisia. In Tunisia, dove la censura era severa prima della rivoluzione del 2011, la gente divenne consapevole della natura dei falsi errori 404 e creò un personaggio immaginario chiamato "Ammar 404" che rappresenta "il censore invisibile".

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.