Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to support Command in REST while doing REST, CQRS and EventSourcing together?

Consider the following coarse grained REST apis for a Contact resource

POST          /api/contacts                             
GET           /api/contacts                             
GET           /api/contacts/:id                         
PUT           /api/contacts/:id                         
DELETE        /api/contacts/:id                         

Consider using eventsourcing for the contact resource, i.e. commands are validated and events are stored. So every event must be stored, including each field level change.

CreateContactCommand -> | Contact("john", "doe", 25) | -> ContactCreatedEvent
FirstNameChangeCommand -> | Contact("jane", "doe", 25) | -> FirstNameChangedEvent
LastNameChangeCommand -> | Contact("jane", "dear", 25) | -> LastNameChangedEvent
AgeChangeCommand -> | Contact("jane", "doe", 30) | -> AgeChangedEvent

Now, combining REST and EventSourcing both.

Doing REST, how the client communicates to the above standard REST APIs for field level changes to generate commands at server side REST end point?

Major question is, how to design REST API so that it can also support the commands eventually supporting eventsourcing?

If anybody could shed light on this, the help would be greatly appreciated.

like image 527
PainPoints Avatar asked Sep 09 '15 09:09

PainPoints


1 Answers

CQRS and event Sourcing is neither an API design principle, nor is it a top-level architecture. Still, if you want to 'expose' your API as a task-based API, you can expose links as part of the contact resource.

GET /contacts/1234

Response

200 OK
<contact>
  <atom:link href="/contacts/1234/first-name" rel="first-name" />
  <atom:link href="/contacts/1234/last-name" rel="last-name" />
  <atom:link href="/contacts/1234/age" rel="age" />
  <first-name>Jane</first-name>
  <last-name>Doe</last-name>
  <age>25</age>
</contact>

The assumption here is that you change the API to a true level 3 REST API.

Also, /contacts/1234 will only accept GET and DELETE (not PUT) requests. If a client wants to change e.g. the first name of a contact, it must follow a link with the relationship type first-name and make a PUT request against that resource:

PUT /contacts/1234/first-name
<first-name>John</first-name>

Anything else than a first-name field PUT here should be ignored or rejected.

Thus, when the service receives a PUT against a first-name resource, it's a command to change the first name of the contact.

This still isn't a proper task-based API because it doesn't capture why the first name changes, but I hope you get the idea.

like image 103
Mark Seemann Avatar answered Nov 06 '22 10:11

Mark Seemann