Come aderire ai principi REST puri quando sono richieste funzionalità diverse in diverse situazioni

6

Abbiamo un'API RESTful che consente la creazione di utenti tramite il POST a un particolare endpoint, api/v1/users

Nel sistema, quando un utente viene creato, viene inviata una e-mail all'utente con il contenuto sulla falsariga di "{Utente autenticato} ti ha appena aggiunto al sistema super-cool e ora puoi fare qualsiasi cosa"

Tuttavia, in alcuni casi, quando un utente viene creato tramite l'API, NON VUOI inviarlo a tali messaggi. Supponiamo che si tratti di una sorta di processo di importazione o qualcosa del genere: lo sviluppatore ha già i suoi dati e non desidera inviare tali email.

Il dibattito nel nostro ufficio è il seguente:

Punto di vista A: "Questo è un esempio di come cadono i servizi web RESTful. Invece di inviare POST a un endpoint per creare una cosa, dovrebbero invece esserci endpoint di comando per ogni funzione che può essere eseguita dal sistema, quindi ogni cosa che puoi fare è rappresentato da un comando e se sono necessari metadati relativi a quel comando, puoi aggiungerlo "

Punto di vista B: "Il fatto che tu non voglia che la cosa x accada quando la cosa y è creata significa che ci sono due tipi di cose y, o cosa y ha uno stato che, se diverso, fa sì che accadano cose diverse quando viene creato, quindi è ancora possibile aderire ai rigidi principi RESTful "

Questa situazione può essere conciliata con puri principi RESTful? I metadati non sono un inquinamento dell'entità "utente", e quindi un argomento per cui esistono comandi per ogni cosa che si può fare all'interno del sistema? (Forse puoi vedere su quale parte dell'argomento cado ...)

    
posta MajorRefactoring 23.11.2016 - 16:49
fonte

5 risposte

6

Questo non è realmente correlato alla "RESTfulness" della tua API, hai avuto determinate logiche di business che volevi applicare quando un utente è stato creato e quella logica è ora cambiata.

Potresti creare un livello inferiore di API con SaveUser e SendEmail e fare in modo che lo script di importazione richiami SaveUser direttamente mentre il livello più alto chiama api entrambi.

Oppure puoi aggiungere o modificare l'endpoint di alto livello per accettare un parametro che indica se inviare o meno l'e-mail.

    
risposta data 23.11.2016 - 17:22
fonte
3

Can this situation be reconciled with pure RESTful principles?

Assolutamente.

Riddle: come faresti con i browser web, le applicazioni e i moduli?

Probabilmente andrebbe qualcosa di simile. L'utente dovrebbe caricare un segno di libro (/ web / A), che avrebbe un sacco di collegamenti, e l'utente avrebbe letto la pagina per trovare un collegamento "crea utente". L'utente dovrebbe seguire quel link a un modulo (/ web / B) che descrive tutte le opzioni di configurazione. La rappresentazione di tale modulo includerebbe un collegamento al form-submission-endpoint (/ web / C), e quando l'utente ha finalmente inviato il modulo, il server sarebbe andato a lavorare creando una nuova risorsa di informazioni da questa richiesta, e alla fine segnalare che una nuova risorsa è stata creata in (/ users / 12345), o qualsiasi altra cosa. Nel frattempo, uno degli effetti collaterali potrebbe essere l'invio di un'email.

Ora introduci il requisito che dovremmo essere in grado di creare un utente senza inviare l'e-mail. Quindi prepariamo una nuova rappresentazione per (/ web / A). L'utente carica il segnalibro, legge la pagina, vede "creare un utente" - non è quello che voglio - continua e alla fine trova "creare un utente senza email". Segue quel link a un modulo (/ web / E) ... la rappresentazione di / web / E probabilmente assomiglia molto alla rappresentazione di / web / C, con l'importante differenza che questo modulo collegamenti a form-submission-endpoint (/ web / F). L'utente invia il modulo e il server - osservando quale modulo è stato inviato a quale endpoint, segnala che una nuova risorsa viene creata a (/ users / 76890) ma senza effetto collaterale send-the-email.

Qual è l'analogico a questa come una API ? web La risposta più comune è quella di sostituire il tipo di media degli invii di moduli con l'applicazione / json e di saltare i bit non necessari: basta documentare lo schema del corpo del messaggio e l'esistenza di endpoint / json / C e / json / F che fanno la cosa giusta.

Qual è l'analogo a questo come un'API pura REST ? Semplicemente rimettendo i link nelle rappresentazioni delle risorse del processo, in modo che il client scopra gli endpoint leggendo le rappresentazioni, piuttosto che leggere fuori dai documenti della band.

Indipendentemente dal fatto che si chiami "diversi endpoint del comando" o "posting to command queues" o "content negotiation" o CQRS o qualsiasi altra cosa non abbia importanza. Il punto principale di REST sta rendendo gli endpoint individuabili , che ti danno come fornitori di servizi la possibilità di spostare i tuoi endpoint come preferisci.

La tua squadra potrebbe voler discutere di questa immagine, tratta da Ian S Robinsons: The Counterintuitive Web (2010)

L'approcciobottomèREST;imessaggisonovincolatidall'interfacciauniforme.Specializzazioneeinnovazionenasconoespandendolerisorseperfareciòdicuihaibisogno.

L'approccioprincipaleèRPC.

L'approcciointermedioèundisastro.

Howard Dierking (2016):

I believe that many API strategies, while well intentioned, end up being hamstrung by a faith-like allegiance to an incorrect understanding of REST.

    
risposta data 02.12.2016 - 05:42
fonte
3

Oltre alle risposte di Ewan e Robert.

Se guardiamo dal punto di vista funzionale, aggiungi utente e Importa utente sono funzioni diverse. Nonostante entrambi potrebbero finire per eseguire gli stessi processi con gli stessi risultati (nel DB).

Sono ancora diversi casi d'uso con diverse connotazioni.

Potresti abilitare un RPC -come endpoint -like per l'importazione di utenti (o qualsiasi tipo di risorsa) invece di " riutilizzo di " POST /API/v1/users

Ad esempio: (Nota: ho usato / rpc ma non ha importanza)

POST /rpc/v1/resources

//Input data model.
{
    "method":"import"
    "params":{
          "resourceClass":"User",
          "resources":[
            {"name":"Jhon", "surname":"Conor"},
            {"name":"Sara", "surname":"Conor"}
          ],
          "notifications":false
     }
}

(Puoi progettare il modello di dati di input che ti serve. Ho preso come riferimento JSON-RPC ) .

Non c'è niente di sbagliato nell'abilitare endpoint diversi , con diversi design / tecniche per scopi diversi .

Non lasciare che principi / tecnologie / parole d'ordine decidano cosa è appropriato e cosa no.

    
risposta data 23.11.2016 - 23:43
fonte
2

Lo scopo principale dello stile architettonico REST è quello di rappresentare risorse su Internet, e per fornire meccanismi per scoprirli .

È ciò che stai cercando di realizzare una di queste due cose? Se non lo è, considera semplicemente di fornire un endpoint sensato che accetta un POST e fa ciò che vuoi.

In alternativa, includi un parametro nell'URL RESTful che governerà il comportamento desiderato.

    
risposta data 23.11.2016 - 17:07
fonte
1

Isn't the metadata a pollution of the "user" entity

Bene HTTP è già un protocollo REST, e la specifica HTTP non contiene nulla riguardo a non inquinare la rappresentazione della risorsa con meta-dati.

Quando si parla di REST e si è in dubbio su qualcosa, basta guardare come funziona il web. Ogni volta che scarichi un file PNG o JPEG su un sito web sul Web, stai scaricando una rappresentazione con tonnellate di metadati. Ad esempio, quale fotocamera ha scattato la foto, il software che l'ha modificata ecc.

HTTP non si preoccupa di questo, invia semplicemente lo stato corrente della risorsa in un formato di rappresentazione che il server e il client comprendono. Il server o il client potrebbero interessarsi di questi metadati e sono liberi di intraprendere qualsiasi azione a loro piace in base a tali informazioni o semplicemente ignorarlo.

Questo è specificamente il vantaggio di REST, se HTTP si preoccupasse di cose di dominio aziendale come se il tuo protocollo di comunicazione si interrompesse ogni volta che hai cambiato il tuo formato di rappresentazione. Invece posso usare un browser web dal 1996 per navigare in un sito web dal 2016. Il browser potrebbe non comprendere il formato di rappresentazione che riceve (cos'è questo HTML v5?) Ma otterrò la risorsa.

Se definisci una rappresentazione di una User di risorse che ha un valore definito lungo le linee di expects_email=true , non ci sono problemi per quanto riguarda il fatto che alcuni non hanno esito.

Il server è libero di fare qualcosa basato su questo o di ignorarlo. Dovresti quindi creare il tuo server web per avere un effetto collaterale che se riceve una nuova risorsa User nello stato di attesa di un'email che invia effettivamente l'email.

Il client non sta dicendo al server di inviare un'email. Sta dicendo al server 'Yo! Ho appena creato un nuovo utente e questo utente è in attesa di una email '. Il client non dice al server altro che 'yo, ecco una nuova risorsa' Questo è il limite a cui REST si prende cura. Ma tu sai che il server invierà un'e-mail e puoi definirla nelle specifiche di rappresentazione in modo che gli sviluppatori client sappiano che ciò accade quando il server ottiene User in quello stato.

    
risposta data 29.11.2016 - 17:31
fonte

Leggi altre domande sui tag