2014-04-16 36 views
11

Sto sviluppando un'API RESTful. Questa è la mia prima API, ma anche il mio primo vero progetto di codifica. Come tale, sto ancora imparando molto su architettura eccAPI RESTful: dove dovrei codificare il mio flusso di lavoro?

Attualmente, ho il mio setup api nei seguenti strati:

  • strato HTTP
  • strato Resource
  • Domain Model/Affari Logic strato
  • Data Access/strato repository
  • Persistent Storage/DB strato

Il problema a cui mi sono imbattuto al momento è dove devo mettere gli oggetti/i gestori del flusso di lavoro? Per flussi di lavoro, intendo codice che valuta quale passo successivo è richiesto dall'utente finale. Ad esempio, un flusso di lavoro di e-commerce. L'utente aggiunge l'articolo al carrello, quindi controlla, quindi inserisce i dati personali, quindi paga. Il flusso di lavoro sarebbe responsabile per decidere quali passi sono successivi, ma anche quali passaggi NON sono consentiti. Ad esempio, un utente non può causare errori nell'API tentando di pagare prima di aver inserito i dettagli personali (forse richiamano l'URI per i pagamenti e tentano di saltare un passaggio). Il flusso di lavoro controllerebbe che tutti i passaggi precedenti fossero stati completati, in caso contrario non avrebbe consentito il pagamento.

Attualmente la logica del flusso di lavoro è nel livello risorse. Sto usando i collegamenti ipermediali per presentare il flusso di lavoro all'utente, ad es. fornendo un link 'next step'. Il problema che ho con questo è che il livello di risorse è un livello superiore e più allineato con la presentazione. Ritengo che sia necessario conoscere troppo il modello di dominio sottostante per valutare efficacemente un flusso di lavoro, ovvero che dovrebbe sapere che deve controllare l'entità personal_detail s prima di consentire il pagamento.

Questo mi porta ora a pensare che i flussi di lavoro appartengano al modello di dominio. Questo ha molto più senso, dal momento che i flussi di lavoro sono parte della logica aziendale e penso che siano quindi nella posizione migliore nel livello dominio. Dopo tutto, sostituisci il Livello risorse con qualcos'altro, e avresti ancora bisogno dei flussi di lavoro sottostanti.

Ma ora il problema è che i flussi di lavoro richiedevano la conoscenza di diversi oggetti di dominio per completare la loro logica. Ora sembra giusto che vada nel suo stesso livello? Tra risorsa e livello di dominio?

  • strato HTTP
  • strato Resource
  • strato Workflow
  • Domain Model/Business Logic strato
  • Data Access/strato repository
  • Persistent Storage/DB strato

Mi sto solo chiedendo se qualcuno ha avuto altre opinioni o pensieri su questo? Come ho detto, non ho esperienza di applicazione passata per sapere dove devono essere collocati i flussi di lavoro. Im davvero solo imparando questo per la prima volta, quindi voglio essere sicuro che sto andando su di esso nel modo giusto.

I collegamenti ad articoli o blog che trattano questo sarebbero molto apprezzati. Ama leggere su diverse implementazioni.

EDIT

Per chiarire, io rilascio che hateoas permette al cliente di navigare attraverso il 'flusso di lavoro', ma ci deve essere qualcosa nel mio API che sa cosa si collega a mostrare vale a dire che è davvero definire il flusso di lavoro che è permesso. Presenta collegamenti relativi al flusso di lavoro nella risorsa, ma in aggiunta convalida le richieste in sincronia con il flusso di lavoro. Mentre sono d'accordo che un cliente probabilmente seguirà solo i collegamenti forniti nella risorsa, il pericolo (e la bellezza) del riposo, è che il suo URI è guidato, quindi non c'è nulla che impedisca a un cliente dispettoso di tentare di saltare i passaggi nel flusso di lavoro fare una supposizione istruita all'URI. L'API deve individuare questo e restituire una risposta 302.

risposta

3

La risposta a questa domanda mi ha richiesto un bel po 'di ricerca, ma in fondo la parte del "flusso di lavoro" non ha nulla a che fare con REST e molto altro sul livello dell'applicazione.

Il mio sistema aveva la logica dell'applicazione e l'API REST troppo strettamente accoppiate. Ho risolto il mio problema refactoring per ridurre l'accoppiamento e ora il flusso di lavoro vive all'interno del contesto dell'applicazione

1

REST ti incoraggia a creare un vocabolario di nomi (utenti, prodotti, carrelli acquisti) rispetto a un set predefinito di verbi (GET, POST, PUT, DELETE). Se segui questa regola, nel tuo esempio il flusso di lavoro è in realtà definito dall'insieme di interazioni che l'utente ha con il tuo sito. È come l'utente usa la tua app, che è realmente definita dall'interfaccia utente. I servizi REST dovrebbero reagire in modo appropriato a richieste di stato non valide, come il tentativo di pagamento con un carrello vuoto, ma l'interfaccia utente può anche impedire tali richieste utilizzando lo script, che è una caratteristica opzionale di REST.

Ad esempio, l'interfaccia utente che visualizza un prodotto per l'utente potrebbe anche visualizzare un collegamento che consente all'utente di aggiungere quel prodotto al carrello (POST shoppingcart/{productId}). Il server non dovrebbe davvero preoccuparsi di come l'utente è arrivato a quel POST, solo che dovrebbe aggiungere quel prodotto al carrello dell'utente e restituire una rappresentazione aggiornata del carrello all'utente. L'interfaccia utente può quindi utilizzare javascript per determinare se visualizzare o meno un collegamento per il pagamento solo se il carrello ha uno o più articoli.

Sembra quindi che il flusso di lavoro risieda al di fuori del servizio REST ed è piuttosto definito dalla navigazione nelle pagine, che interagiscono con i servizi REST quando l'utente richiede le cose. È certamente possibile che si abbiano flussi di lavoro interni che devono verificarsi all'interno dell'applicazione in base all'impostazione degli stati da parte dell'utente. Ma ciò che sembra descrivere è un'interazione dell'utente all'interno del sito, e mentre questo è davvero un flusso di lavoro, sembra meglio definito dalle tue UI che da un componente/livello dedicato lato server.

+0

Non sono d'accordo con quello che hai detto. Un'API REST utilizza HATEOAS per consentire all'utente di definire un "flusso di lavoro" attraverso l'app. Ma quello che stai dicendo è che dovremmo consentire all'utente (o all'app client) di definire la logica e fare tutto ciò che vogliono !! Questo è chiaramente sbagliato. Quindi, quello di cui sto parlando è garantire che il "flusso di lavoro" che il cliente sta seguendo sia permesso. Alcune parti dell'API devono essere responsabili dell'elaborazione di quali collegamenti possono essere visualizzati con una risorsa (il flusso di lavoro) e anche di convalidare che le richieste non sono al di fuori del flusso di lavoro (es. Restituire un 302) vedere l'aggiornamento sopra –

+0

Perché il server è fornendo javascript al client che il client usa per determinare se visualizzare o meno un collegamento, il server sta sostanzialmente estendendo la sua logica sul client e quindi sta ancora determinando il flusso di lavoro. Non c'è nulla che ti impedisca di iniettare un livello aziendale nella tua architettura tra l'interfaccia utente e i servizi REST, ma quando lo fai, a seconda di come lo implementa, l'interfaccia utente potrebbe non comunicare più RESTfully. –

+0

E dove dovrebbe vivere questo livello aziendale? –

-1

Si consiglia di riorientare l'architettura lungo le linee di DDD (Domain Driven Design) e magari utilizzare un MSA, in questo modo puoi passare dal flusso di lavoro orchestrato all'EDA e alla coreografia dei micro processi.

+0

Perché? Forse fornire alcuni pro e contro. Cosa rappresentano gli altri acronimi? Una risposta molto "manageriale" finora. –

1

Si tocca la parte del flusso di lavoro (alias logica aziendale) di un'API. Tecnicamente questa è una preoccupazione separata dalla parte API che è l'interfaccia. Certo, come dici tu, HATEOAS ti permette di suggerire determinate azioni che sono valide, ma dovresti fare attenzione a mantenere statelessness.

Nelle applicazioni REST, non deve essere presente lo stato di sessione memorizzato sul lato server. Invece, deve essere gestito interamente dal cliente.

Quindi, se c'è stato di sessione sul server, non è REST.

Per l'esempio del carrello, è possibile salvare lo stato in un livello di caching separato come Redis.Per quanto riguarda i tuoi flussi di lavoro. Non si vorrebbe mettere la logica di business come il calcolo del carrello acquisti o del conto totale in un modello di dominio. Questo sarebbe aggiunto al livello di servizio.

Hai parlato di utenti maliziosi che indovinavano gli URL. Questa è sempre una preoccupazione e dovrebbe essere gestita dalla tua sicurezza. Se l'URL per cancellare un utente è DELETE/user/3782 ... possono facilmente indovinare come eliminare tutti gli utenti. Ma non dovresti affidarti solo a nascondere gli URL. È necessario disporre di veri controlli di sicurezza e accesso all'interno degli endpoint per verificare se ciascuna richiesta è valida.

Questa è la stessa soluzione per le preoccupazioni relative al carrello della spesa È necessario concedere un token che allegherà le informazioni sullo shopping e utilizzarlo per convalidare ogni azione, indipendentemente dal fatto che conoscesse o meno l'URL corretto. Non ci sono scorciatoie quando si tratta di sicurezza.