2016-06-17 49 views
7

Sono nuovo di DDD e sto cercando di capire come aggiornare l'aggregato utilizzando un verbo PUT.Aggiornamento DDD tramite REST

Se tutte le proprietà nell'aggregato dispongono di setter privati, è ovvio che è necessario disporre di una serie di funzionalità per ogni esigenza aziendale. Per un esempio

supportTicket.Resolve(); 

E 'chiaro per me che posso raggiungere questo obiettivo con un punto finale, come /api/tickets/5/resolve, ma cosa succede se voglio fornire un modo per aggiornare tutto il biglietto atomico?

A titolo di esempio, l'utente può fare una richiesta PUT per /api/tickets/5 con un corpo in seguito

{"status" : "RESOLVED", "Title":"Some crazy title"} 

Ho bisogno di fare qualcosa di simile nel ApplicationSercvice

if(DTO.Status != null && dto.Status == "RESOLVED") 
    supportTicket.Resolve(); 
if(DTO.Title != null) 
    supportTicket.setNewTitle(DTO.title); 

Se questo è il caso e cambiare il titolo del biglietto ha qualche logica aziendale per evitare di cambiarlo se il ticket viene risolto, dovrei prendere in considerazione qualche tipo di priorità nell'aggiornare l'aggregato, o sto considerando tutto questo completamente sbagliato?

+0

Penso che questo sia più design API rispetto a DDD, ma controlla questo articolo: https://www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling - tl; dr; sfuggire al CRUD. – acid

risposta

6

Domain Driven Design for RESTful Systems - Jim Webber

cosa se voglio fornire un modo per aggiornare tutto il biglietto atomico?

Se si desidera aggiornare l'intero ticket atomicamente, aggregare fossi; gli aggregati sono lo strumento sbagliato nella tua casella se quello che vuoi veramente è un negozio di valore chiave con semantica CRUD.

Gli aggregati hanno senso solo se sono regole aziendali che il dominio deve applicare. Non costruire un trattore quando tutto ciò di cui hai bisogno è una pala.

A titolo di esempio, l'utente può fare una richiesta PUT a/API/biglietti/5

che sta andando a fare un pasticcio. In un'implementazione CRUD, sostituire lo stato corrente di una risorsa inviandogli una rappresentazione di un nuovo stato è appropriato. Ma questo non è assolutamente adatto per gli aggregati, perché lo stato dell'aggregato non è sotto il controllo dell'utente, del cliente/editore.

L'idioma più appropriato è quello di pubblicare un messaggio su un bus, che quando gestito dal dominio avrà l'effetto collaterale di ottenere le modifiche desiderate.

PUT /api/tickets/5/messages/{messageId} 

ORA il tuo servizio di applicazione guarda il messaggio e invia i comandi al aggregata

if(DTO.Status != null && dto.Status == "RESOLVED") 
    supportTicket.Resolve(); 
if(DTO.Title != null) 
    supportTicket.setNewTitle(DTO.title); 

Questo è OK, ma in pratica la sua molto più comune per rendere il messaggio esplicito su ciò che è di essere fatto.

{ "messageType" : "ResolveWithNewTitle" 
, "status" : "RESOLVED" 
, "Title":"Some crazy title" 
} 

o addirittura ...

[ 
    { "messageType" : "ChangeTitle" 
    , "Title" : "Some crazy title" 
    } 
, { "messageType" : "ResolveTicket" 
    } 
] 

In sostanza, si vuole dare l'applicazione abbastanza contesto che può fare la convalida messaggio vero e proprio.

diciamo che ho avuto aggregati che incapsulate logica di business necessaria, ma oltre a questo c'è una nuova domanda di funzionalità di aggiornamento atomica e sto cercando di capire un modo migliore per affrontare questo.

Quindi il modo giusto per affrontare questo è il primo ad affrontare il problema a livello di dominio - sedersi con i vostri esperti del settore, assicurarsi che tutti capiscono l'esigenza e come esprimere nel linguaggio onnipresente, ecc.

Implementare tutti i nuovi metodi necessari nella radice aggregata.

Una volta che il caso di utilizzo è correttamente supportato nel dominio, è possibile iniziare a preoccuparsi delle risorse seguendo il modello precedente: la risorsa accetta solo la richiesta in arrivo e richiama i comandi appropriati.

+0

Capisco che gli aggregati non sono la soluzione ideale, ma diciamo che avevo aggregati che incapsulavano la logica aziendale necessaria, ma oltre a questo c'è una nuova richiesta di funzionalità di aggiornamento atomico e sto cercando di capire il modo migliore per affrontarlo. – Robert

+0

@Robert Non si devono mischiare sia le operazioni CRUD che le operazioni comportamentali sullo stesso aggregato. Non vedo dove sarebbe mai utile comunque. – plalx

+0

Potrei implementare Hypermedia quando OTTENERE il resouce e descrivere tutte le possibili azioni che possono essere fatte a quella risorsa, così i consumatori api possono vedere la mia logica di business e sapere esattamente cosa può essere cambiato e come farlo? – Robert

0

Probabilmente hai ragione. Ma probabilmente è più saggio incapsulare tale logica all'interno del ticket stesso, facendo un metodo "change()", ricevendo un changeCommandModel (o qualcosa di simile), in modo da poter definire le regole di business all'interno dell'oggetto dominio.

0
if (DTO.Status != null && dto.Status == "RESOLVED") 
        supportTicket.Resolve(DTO.title); 

Cambierò il metodo sottostante per prendere il titolo come parametro, questo chiarisce l'azione di risoluzione. Quella seconda se e la convalida si desidera nel metodo del dominio. È davvero una preferenza, ancora più importante è il messaggio e sono d'accordo con la seconda opzione di @VoiceOfUnreason.

+0

questo andrebbe bene se fosse l'unico scenario possibile, ma questo non si fermerebbe se l'utente avesse inviato qualche altro parametro nel corpo. – Robert

2

La modifica del titolo è un requisito per la risoluzione di un ticket? In caso contrario, non dovrebbero essere la stessa azione in DDD. Non vorrai risolvere il ticket se il nuovo nome non è valido e non vorrai cambiare il nome se il ticket non è risolvibile.

Effettuare 2 chiamate per eseguire le 2 azioni separate. Ciò consente anche flessibilità come, il titolo può essere modificato immediatamente, ma forse "risolvere" il ticket darà il via a un flusso di lavoro complesso e dispendioso (asincrono) prima che il ticket venga effettivamente risolto. Forse è necessario che un manager firmi? Non vuoi che la chiamata cambi il "titolo" legato a quel mix.

Se necessario, creare qualcosa per orchestrare più comandi come da commento di @ VoiceOfUnreason.

Ove possibile, mantenere le cose separate e il codice per utilizzare i casi anziché minimizzare gli interazioni con le entità.