Implementazione di un servizio REST composito

6

Negli anni passati ho avuto la necessità di implementare la logica di business in un tipo di servizio più ampio, orchestrando più spesso una manciata di microservizi atomici.

Operazioni come "ricerca e aggiornamento del documento, quindi e-mail team delle risorse umane", "firma il contratto e aggiorna ERP", "avvia il lavoro batch ERP".

Ma sembra sempre strano mappare questi servizi compositi a una struttura RESTful. Quali sono alcuni modi comuni per gestire implementazioni come queste?

Non sto chiedendo dove dovrebbe essere posizionata questa logica (middleware o altro) ma come dovrebbero essere costruiti gli endpoint REST. Negli esempi forniti sopra cosa costituirebbe una risorsa e con quale verbo?

/updatedocument con POST ?

/erp/batch/start con PUT ?

    
posta Mike 19.03.2016 - 12:20
fonte

1 risposta

5

Ho creato molti servizi ipermediali nel corso degli anni e ho sentito questo dolore. Si riduce alla prospettiva. Quindi, farò del mio meglio per descrivere la mia esperienza.

REST, a prima vista, è stato ingenuamente descritto come aderente al vincolo architettonico utilizzando la creazione, l'aggiornamento, il recupero e l'eliminazione di risorse . Molte persone identificano questo semplicemente con gli oggetti CRUD che vengono mantenuti in un database. Sebbene una buona parte dei microservizi lo faccia, è generalmente anemico e fornisce poche funzionalità in caso contrario.

Quindi, cos'è esattamente una risorsa ? Per me, le risorse forniscono anche astrazioni di funzionalità e processi. Le rappresentazioni di una risorsa sono i dati che mostrano lo stato di tale funzionalità o processo.

Prendiamo il tuo esempio di un "lotto ERP". Questo è chiaramente un processo complesso e può coinvolgere più servizi interni. C'è molto probabilmente qualcosa che mette in correlazione questa attività. Questi dati correlati sono la tua risorsa batch. È lo stato di un lotto. Per soddisfare il vincolo ipermediale REST, creiamo una nuova risorsa batch eseguendo un POST:

POST /erp/batch

Uso qui un POST invece di PUT perché stiamo creando una nuova risorsa e non conosciamo l'URL esatto della risorsa. I POST non sono idempotenti . Ogni invocazione crea una nuova risorsa unica. Si noti inoltre che gli URL sono nomi singolari e non terminano in un verbo.

La risorsa che stiamo creando è un processo batch concettuale. Questa azione POST dovrebbe memorizzare lo stato iniziale, avviare il flusso di lavoro del processo in modo asincrono e restituire l'URL della risorsa nell'intestazione Location . Il processo del flusso di lavoro non ha bisogno di per essere completato prima di restituire un URL e dovrebbe aggiornare periodicamente i dati della risorsa. Come ciò accade dipende dalla tua architettura interna. Potrebbe essere diretto, guidato dagli eventi o qualsiasi altra cosa.

Il client, a sua volta, può utilizzare quell'URL per recuperare la risorsa batch, dove la rappresentazione è lo stato corrente del processo batch (ad esempio):

GET /erp/batch/917163

La rappresentazione del tuo batch cambierà mentre il tuo processo si muoverà attraverso il suo flusso di lavoro. Lo stato del tuo gruppo, eventuali errori o avvertenze che possono accadere e risultati finali. Il fatto che i dati delle risorse cambino, il tuo cliente dovrebbe sapere. Qui è dove vengono usate le intestazioni cache e le richieste condizionali GET.

Queste due operazioni sono probabilmente il minimo necessario. Ma cosa succede se si desidera annullare un lotto? Come possiamo farlo RESTfully? Ci vuole un sacco di riflessioni Ho visto molte opzioni:

  • Alcuni servizi espongono un flag "cancel" come parte della rappresentazione della risorsa e utilizzano un'operazione PUT. Tuttavia, le operazioni PUT aggiornano la intera risorsa nel suo complesso facendo passare al client una nuova rappresentazione di quella risorsa. Questo è OK se la rappresentazione è piccola e a basso rischio, ma può consentire ai clienti di rovinare il processo batch.
  • Al posto di PUT, alcuni usano PATCH (un'estensione HTTP WebDAV) per fare un aggiornamento parziale della risorsa e impostare questo flag "cancel". Di nuovo, non RESTful.
  • Alcuni usano DELETE per comportarsi come un annullamento. CANCELLARE significa che stiamo rimuovendo la risorsa dall'esistenza. Il problema qui è che eseguire un GET sull'URL di una risorsa DELETEd dovrebbe restituire un errore di livello 400, ma è comunque necessario che i dati di correlazione siano presenti. Sembra più simile a un'operazione calzante.

La mia preferenza è creare una risorsa cancellazione :

PUT /erp/batch/917163/cancellation

Se il servizio segue il vincolo ipermediale, il client può scoprire la possibilità di annullare seguendo un link nella risorsa batch. Ho usato un metodo PUT perché conosco l'URL di questa cancellazione e posso accettare solo esattamente una cancellazione. Avrei potuto facilmente fare un POST per supportare più richieste di cancellazione tracciabili in modo univoco:

POST /erp/batch/917163/cancellation

Come il batch, creerà anche un nuovo URL. La rappresentazione dell'annullamento può ritornare al collegamento. Le possibilità sono infinite.

Spero che questo ti dia una nuova prospettiva. Buona fortuna.

    
risposta data 20.03.2016 - 06:46
fonte

Leggi altre domande sui tag