Esecuzione di una ricerca di nome utente prima di registrare un utente pur conformandosi alla filosofia REST

1

Ho un servizio REST basato su Spring MVC. JSON è l'unico formato di interscambio per qualsiasi cliente per parlare con questo servizio.

Sto lavorando per implementare un flusso di lavoro per la registrazione degli utenti. Così ho creato un endpoint (/ register, payload = User object in JSON) che accetta l'entità User e fa la cosa. Quindi sto trasferendo lo stato di un oggetto che mi rende contento di aderire alla filosofia REST (credo).

La mia domanda è: prima che possa registrare un utente, ho bisogno di controllare se il nome utente è già esaurito. Quindi posso creare un nuovo endpoint / registro / nome utente / Ma questa idea suona male e non RESTful affatto mentre sto usando l'endpoint per eseguire un'azione, non il trasferimento di stato. E sembra che sto invocando un metodo per eseguire un'azione (Remote RPC). Come posso pensare questo in termini di REST?

    
posta user6123723 21.10.2015 - 23:13
fonte

4 risposte

6

I'm using the endpoint to perform an action, not transfer of state.

In realtà, stai trasferendo lo stato. Il client sta inviando la nuova entità utente proposta al server. Tuttavia, il server ha le proprie regole da applicare, quindi deve rifiutarsi di creare un utente se il suo identificativo univoco esiste già.

C'è già un codice di errore HTTP per questo. Come ha sottolineato @tom, il codice di risposta the 409 Conflict è accettabile per quello. Significa fondamentalmente What you asked me to do is perfectly legal in from your standpoint. I am simply unable to fulfill your request because it is in conflict with something outside of your control rispetto ad altri codici di risposta che si concentrano su richieste client inappropriate.

Per quanto riguarda la tua preoccupazione riguardo all'utilizzo di REST per eseguire un'azione in questo caso, non sono d'accordo, ma sono contento che tu stia pensando a questo. Ho visto sviluppatori creare "servizi REST" denominati cose come GET /whatever/updateWidget , che chiaramente non è un modo di pensare RESTENTE.

Stai eseguendo un'azione solo nel senso che stai creando una nuova risorsa. Ma quella risorsa si basa sullo stato che hai trasferito. Devi crearlo in qualche modo.

Se restituisci un codice di errore significativo come 409 , non vedo alcun problema con il tuo approccio.

    
risposta data 22.10.2015 - 02:27
fonte
2

Quando un client tenta di aggiungere un duplicato, vorrei restituire un 409 conflitto . Una 400 cattiva richiesta (con errore di spiegazione nella risposta) andrebbe bene e probabilmente è una pratica più comune.

Tuttavia, la giuria è fuori su questo. REST non chiarisce cosa fare in queste situazioni. Vedere link

    
risposta data 22.10.2015 - 01:09
fonte
2

Per i principianti, e penso che tu sia già su questo, non inventare nuovi verbi e inserirli nell'albero. Se ti accorgi di volerlo fare, fermati e chiediti dove nel modello dovrebbero essere contenuti i dati, quindi POST lì.

Creare un nuovo utente dovrebbe essere un'operazione che fai contro la stessa parte dell'albero che usi per ottenere quelle che già esistono. Ad esempio, dovresti GET /users/lanceboyle per recuperare le informazioni utente di Lance Boyle, quindi dovresti essere POST ing nella stessa posizione per crearne uno nuovo (ad esempio POST /users/duanepipe ).

La tua situazione sembra colpire i punti principali per un codice di ritorno di 409 . Da RFC 7231 (sottolineatura mia):

The request could not be completed due to a conflict with the current state of the resource.

Se ci sono già dati in /users/warrenpease , il suo stato è "esistente". Provando a POST una seconda copia nella stessa posizione è in conflitto con quello stato perché non puoi crearne uno nuovo di quello che già esiste.

This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request.

Ancora una volta, l'utente (richiedente) può risolvere questo problema selezionando un nome utente diverso e POST inserendolo in una posizione che non esiste.

    
risposta data 22.10.2015 - 02:37
fonte
0

Se vuoi che il controllo di unicità del nome utente venga eseguito come parte della creazione di un account, puoi lasciare che "POST / account" restituisca 409 se esiste già un account per quel nome utente. Vedi la panoramica dei codici di stato HTTP . Nel corpo della risposta, è possibile restituire un messaggio di errore appropriato. Se si dispone di una convenzione per specificare esattamente quale campo non è valido nella risposta all'errore, è possibile utilizzare tale convenzione per indicare che il nome utente sta causando un problema (ad es. Per evidenziare quel campo sullo schermo). Risposta di esempio 409:

{
    "message" : "Unable to register new account",
    "errorFields" : [
        { "field" : "userName", "message" : "An account with this user name already exists" },
        { "field" : "password", "message" : "Password too weak" }
    ]
}

Tuttavia, penso piuttosto in una direzione totalmente diversa. In tali situazioni è comune che il client debba verificare esplicitamente un nome utente duplicato prima che tenta di creare un account, ad esempio, non appena l'utente lascia il campo del nome utente. In tal caso, l'app client deve utilizzare il metodo HTTP "HEAD". Vedi le specifiche dei metodi HTTP . Il server restituisce 200 se esiste già un account per quel nome utente e 404 se l'account non esiste.

Supponi / account rappresenta la raccolta di account e / account / xxx rappresenta un account individuale per il nome utente xxx, quindi il client deve eseguire HEAD / accounts / xxx per verificare se l'utente xxx ha già un account. Idealmente, il client non aggiunge semplicemente "/ xxx" a "/ accounts", ma usa un collegamento basato su modello, / accounts / {username}, fornito da un'altra risorsa.

Tuttavia, non inserirò i nomi utente nel percorso. Vorrei utilizzare invece le chiavi tecniche, ad es. / accounts / accountID rappresenta un singolo account, dove accountID è una chiave tecnica. In tal caso, se l'app client deve controllare se il nome utente xxx è già in uso, può eseguire HEAD / accounts? UserName = xxx (ancora una volta, un'altra risorsa dovrebbe fornire un collegamento basato su modelli per farlo).

    
risposta data 02.11.2015 - 17:53
fonte

Leggi altre domande sui tag