19

I came across Event Sourcing design and I would like to use in an application where a REST client is needed (RESTful to be precise). However I fail to connect these together as REST is quite CRUD-like and event sourcing is task based. I was wondering how can you designed the creation of commands based on requests to REST server. Consider this example:

With REST you can put a new state to the resource called File. In one request you can send new file name, you can change the parent folder and/or change owner of the file and so on.

How to construct the server so I can use event sourcing. I was thinking about these possibilities:

  1. Determine on server which fields were changed and create appropriate commands (RenameFileCommand, MoveFileCommand, ChangeOwnerCommand, ...) and dispatch these individually. However in this setup, each of the command can fail leaving others out of transaction and thus out of "atomic" change to the resource.

  2. Dispatch only one command (UpdateFileCommand) and in the command handler, more precisely in the aggregate, determine which fields were changed and send individual events instead (FileRenamedEvent, FileMovedEvent, OwnerChangedEvent, ...)

  3. This one I don't like at all: In the request to the server I would specify in the headers which command to use, because the UI is still task based (but communication is done via REST). However it will fail in any other use of REST communication (e.g. in external apps) as they are not bound to change only the one field in one request. Also I bring quite a big coupling into the UI, REST, and ES-based backend.

Which one would you prefer or is there any better way to handle this?

Side note: app written in Java and Axon Framework for event-sourcing.

Arseni Mourzenko
  • 134,780
  • 31
  • 343
  • 513
redhead
  • 581
  • 6
  • 15
  • Certainly not the 3rd. I would do the 1st, but I have to think about it. – inf3rno Feb 18 '15 at 16:46
  • Is you question about whether a single HTTP request can result multiple Commands? Do I understand well? Imho. it should be able to do so, but I haven't read about DDD for a while, so I have to check a sample code about how to implement this. – inf3rno Feb 18 '15 at 16:51
  • I found an example, but it's CRUD. https://github.com/szjani/predaddy-issuetracker-sample/blob/3.0/src/hu/szjani/presentation/web/controllers/IssueController.php I'll ask the author what is his opinion, he knows more about DDD than me. – inf3rno Feb 18 '15 at 17:09
  • 1
    Mine is that you should use multiple commands in a "unit of work" if you want immediate consistency. If you are talking about eventual consistency then the question does not make sense to me. Another possible solution to send a CompositeCommand which can contain the Commands you want to execute atomical. It can be a simple collection, the only thing matters that the bus can handle it properly. – inf3rno Feb 18 '15 at 17:17
  • 1
    According to him you should try to achieve 1:1 relationship between commands and HTTP requests. If you cannot do it (that is a bad smell), then you should use bulk (I called it composite) to make it atomic. – inf3rno Feb 18 '15 at 18:59
  • Correct. If multiple commands are dispatched in single unit of work, it could work. Actually, I was thinking about CompositeCommand of some sort too and I think it should be possible. But, thinking now about the 2nd proposition, it could work as well, because what else knows about the internal state (to determine which fields were actually changed) than the aggregate? Sending these events from one update command handled in aggregate will still be in one transaction. The worse part is I will have multiple writes to database for each field. Hm.. – redhead Feb 19 '15 at 07:33

2 Answers2

14

I think you may have a user-process to implementation mismatch here.

First: will a user honestly want to perform multiple changes to a file simultaneously? A rename (which may or may not include a change of path?), change of ownership, and perhaps change of file contents (for sake of argument) seem like separate actions.

Lets take the case where the answer is "yes" - your users really do want to make these changes simultaneously.

In that case, I'd strongly recommend against any implementation that sends multiple events - RenameFileCommand, MoveFileCommand, ChangeOwnerCommand - to represent this single user intent.

Why? Because events can fail. Maybe its extremely rare, but your user submitted an operation that looked atomic - if a single one of the downstream events fails, then your application state is now invalid.

You are also inviting race hazards on a resource that is clearly shared between each of the event handlers. You will need to write "ChangeOwnerCommand" in such a way that the file name and file path do not matter, because they could be out of date by the time the command is received.

When implementing a non-event driven restful system with moving and renaming files, I prefer to ensure consistency by using something like an eTag system - ensure that the version of the resource being edited is the version that the user last retrieved, and fail if it has been modified since then. But if you are dispatching multiple commands for this single user operation, you will need to increment your resource version after each command - so you have no way to know that the resource the user is editing really is the same version as the resource they last read.

What I mean by that is - what if someone else performs another operation on the file at nearly the same time. The 6 commands could stack up in any order. If we had just 2 atomic commands, the earlier command could succeed and the later command could fail "resource has been modified since it was last retrieved". But there is no protection against this when the commands are not atomic, so system consistency is violated.

Interestingly there is a movement toward something like event based architecture in REST, called "Rest without PUT", recommended in the Thoughtworks technology radar, Jan 2015. There is a considerably longer blog about Rest without PUT here.

Essentially, the idea is that POST, PUT, DELETE and GET are fine for small applications, but when you need to start assuming how put and post and delete might be interpreted at the other end, you introduce coupling. (e.g. "when I DELETE the resource associated with my bank account, the account should be closed") And the solution proposed is to treat REST in a more Event sourced way. i.e. Lets POST the user intent as a single event resource.

The other case is simpler. If your users don't want to do all those operations simultaneously, don't let them. POST an event for each user intent. Now you can use etag versioning on your resources.

As for the other applications which are using a very different API to your resources. That smells like trouble. Can you construct a facade of the old API on top of your RESTful API and point them at the facade? i.e. expose a service that performs multiple updates to a file in sequence via the REST server?

If you neither build the RESTful interface on top of the old solution, nor build a facade of the old interface on top of the REST solution, and attempt to maintain both APIs pointing at a shared data resource, you will experience major headaches.

perfectionist
  • 627
  • 7
  • 15
  • I can see the mismatch, however, by REST in principle it is possible to update the state of multiple fields by PUTting the new state to the resource (by some representation). This is how REST works by definition - representational state transfer, the down-side is that the user's intent is lost in the process. Also, REST is almost a standard for external API. I merely want to design the app so I can use both. Removing PUT is like workaround because of ES. From what I can see, one update command emitting multiple events is doable as long the command and event handling is in one transaction. – redhead Feb 17 '15 at 14:37
  • Etag is something I would like to do anyway. Also your link to "longer blog post" is the same as the first link. – redhead Feb 17 '15 at 14:41
  • I'll come back to this after some consideration with more thoughts re PUT. Certainly, removing PUT isn't just "a workaround for ES". I've fixed the blog link. – perfectionist Feb 17 '15 at 15:35
6

Just now I ran into the following article, which encourages specifying the command names in the request to the server in the Content-Type header (while following 5 levels of media type).

In the article, they mention the RPC-style is bad for REST and suggest extending Content-Type to specify the command name:

One common approach is using RPC-style resources for example /api/InventoryItem/{id}/rename. While this seemingly removes the need for arbitrary verbs, it is against REST's resource-oriented presentation. We need to be reminded that a resource is a noun and HTTP verb is the verb/action and self-descriptive messages (one of the tenets of REST) are the vehicle to convey other axes of information and intent. In fact the command in the payload of the HTTP message should be enough to express any arbitrary action. However, relying on the body of the message has problems of its own since the body is usually delivered as a stream and buffering the body in its entirety before identifying action is not always possible nor wise. Here we present an approach based on level 4 (domain model) of 5LMT where the command type is presented as a parameter of the Content-Type header:

PUT /api/InventoryItem/4454c398-2fbb-4215-b986-fb7b54b62ac5 HTTP/1.1
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Content-Type:application/json;domain-model=RenameInventoryItemCommand`

The article is here: http://www.infoq.com/articles/rest-api-on-cqrs

You can read more about 5 levels of media type here: http://byterot.blogspot.co.uk/2012/12/5-levels-of-media-type-rest-csds.html


Although they are exposing the domain events to the REST API, which I would consider a bad practise, I like the solution as it doesn't create a new "protocol" solely for CQRS, be it sending command names in the body or in extra header, and stays true to RESTful principles.

redhead
  • 581
  • 6
  • 15