Pergunta

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.

Foi útil?

Solução

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.

Outras dicas

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.

Licenciado em: CC-BY-SA com atribuição
scroll top