There was a talk on REST+CQRS at DDDX 2011, see skillsmatter.com for
video. Admittedly the speaker just scratched the surface of these questions.
I'd say you are correct in that you wouldn't expose your domain model.
You would PUT new commands, maybe GET the status of pending commands,
DELETE pending commands, GET parts of the readmodel (aka query).
In addition you would probably POST to subscribe to new events (not
necessarily "events" as in "event sourcing" but rather application
events and notifications of changes to the readmodel).
Hence the resources are the available commands and queries and available
event publishers. Those can be advertised as part of a RESTful services
resonse.
Cheers,
Phil
The main problem with REST is that most of the article authors/bloggers
suggest that you should expose your domain model, which is insane. If
you instead expose your usecases, i.e. commands and queries, as
resources which can be manipulated with representations, it's all good.
Works like a charm. Main problem is that there is no decent framework,
yet, that makes this easy to do. Working on that...
/Rickard
I think PUTting commands is missing a beat with REST.
== POST /customer/<id>/address == carries no information on why that address was changed.
== PUT /customer/<id>/commands Content-Type: application/json; charset=utf-8 Id: <commandid> CustomerMovedCommand { Movedto:<newaddress> } ==does so.
== MovedTo /customer/<id> Content-Type: application/json; charset=utf-8 Id: <commandid> { Address:<newaddress> } ==
I think PUTting commands is missing a beat with REST.
I beg to differ ;)
That kind of API brings us right back into CRUD-space, and thus away from DDD.
==
POST /customer/<id>/address == carries no information on why that address was changed.
== PUT /customer/<id>/commandsdoes so.Content-Type: application/json; charset=utf-8Id: <commandid> CustomerMovedCommand { Movedto:<newaddress> } ==
Now, you could generate new http verbs for each command in order to transport the intent.
E.g.
== MovedTo /customer/<id>Content-Type: application/json; charset=utf-8Id: <commandid> { Address:<newaddress> } ==
This, however, leads to an RPC style API. See the cited talk by Jim Webber at DDDX for a brief discussion of using the standard four http verbs versus extending http.
The charm of CQRS is that messages (commands) are encapsulated in objects capable of carrying meta information and being processed (e.g. passed along dynamically configured command handler chains).
Cheers
Phil
Agree. It's an anti-pattern to expose domain models like that.
> ==
> POST /customer/<id>/address
> ==
>
> carries no information on why that address was changed.
>
>
> ==
> PUT /customer/<id>/commands
> Content-Type: application/json; charset=utf-8
> Id:<commandid>
>
> CustomerMovedCommand { Movedto:<newaddress> }
> ==
>
> does so.
> Now, you could generate new http verbs for each command in order to
> transport the intent.
I prefer creating resources for commands and queries, e.g.:
GET /<usecasename>/<id>/
-> links to valid commands, e.g.
GET /<usecasename>/<id>/updateaddress
-> form for updating address
POST/PUT /<usecasename>/<id>/updateaddress
-> list of events caused by command, or error
I.e. commands and queries are made into explicit resources, supporting
as many verbs as makes sense. This makes it really easy to do UI's,
since by checking the list of links in the GET on ../<id>/ you can
determine what buttons or other UI fields should be enabled. If, for
example, the current user is not allowed to change the address, or the
connection to the underlying LDAP server is down, then the link to
"updateaddress" is missing, and the UI can react accordingly (disable
buttons/fields, or hide them entirely).
To determine whether to use POST or PUT on /updateaddress I add a class
"idempotent" on the link, but you can also use the "Allow" header in the
GET call to determine this.
I put "<usecasename>" in the above, because the URL should reflect the
usecase and not the domain model. "customer" is not a usecase,
typically. Replace with whatever makes sense in your domain.
/Rickard
Because having a usecase called "customer" is really really weird. That
sounds like a domain name, and not a usecase name, is what I mean.
I can compare with the problem I ran into in my own app. I used to have
this:
/user/rickard/
from which I could do two commands: changepassword and resetpassword.
But that becomes REALLY funky when you try to do authorization and
linking properly, since they are part of two different client usecases.
So instead I changed this to:
/account/ (my own user is implied)
/administration/server/user/rickard/
i.e. the usecases are "account management" and "user administration",
with changepassword and resetpassword respecticaly. With that change it
became much more easy to handle, on the server and client. So, again,
"customer" to me doesn't sound like a usecase. It sounds like exposing
the domain model, and that breaks down fantastically when you try to do
HATEOAS properly.
/Rickard
Again, that's a terrible usecase name, because that is "what the system
is", whereas usecase names should reflect "what the system does". Good
luck creating sensible links that guides the user agent to perform
application state transitions.
/Rickard
When designing a service that responds to commands or queries, do you think making it RESTful is beneficial? In some ways I think that CQRS and REST are conflicting paradigms. REST fully exposes resources to the client - resources that can be created, updated and deleted. On the other hand CQRS hides the resources (entities) behind commands - they can be changed only by issuing very specific commands.Thoughts / comments?
You would PUT new commands, maybe GET the status of pending commands, DELETE pending commands, GET parts of the readmodel (aka query).
In addition you would probably POST to subscribe to new events (not necessarily "events" as in "event sourcing" but rather application events and notifications of changes to the readmodel).
Hence the resources are the available commands and queries and available event publishers. Those can be advertised as part of a RESTful services resonse.
To me there is a big difference here. First of all, I can create a link
to the first, but no to the second, thus informing the client about the
possible next states. Also, I can do a GET on the first and either get
200 (=it's ok to perform the command) or 404 (=it's not ok to perform
the command), which is very important from a UI point of view. Never
allow UI's to "try" commands that are sure to fail. The first variant
helps, whereas the second don't.
/Rickard
What is wrong with exposing my domain model's aggregate roots as resources over http? The client can still think of things as "commands" since they have to pass the command name as part of the url and as Rickard says there will be a uri that represents that aggregate root now. Maybe it could be more clear to use a query string parameter?POST /customer/1?command=changeName{ "Name": "Robert" }
Still, there is a subtle difference in "changeAddressTo" and
"MoveToNewAddress", but whether this difference is important depends on
the business case.
There is some debate as to whether to POST or PUT commands.
I think I would prefer PUT /customer/<id>/MoveToNewAddress/<cmdid> where
the cmdid is defined by the sender
This way, sending the command is idempotent.
Cheers,
Phil
Everything. Unfortunately that model is what almost all bloggers
suggest, which is causing a mess beyond belief.
Let's start with this: how do you create links in the hypermedia to
guide the client to achieve state transitions that are ok according to
the application usecases? (This is what the REST thesis says that you
should do, so this is mandatory)
/Rickard
How do you use hypermedia to allow client to find out what commands are
available and how to invoke them?
/Rickard
That's not true. It *is* a mandatory prescription. "If you apply these
constraints, you get these results". I.e., if you don't apply the
constraints, you don't get the results. You get a "Web API", which could
be JUST FINE, but it's not REST. With the Maturity Levels you need to
note that it is only at Level 3 that you get REST. The other levels are
"Web APIs", or "HTTP APIs", or whatever you want to call them. Which is
FINE, if that is what you want.
> When implementing apps in a RESTfull manner you expose business
> capabilities or application protocol with your resource representations
> sprinkled with hypermedia controls.
> That means you are guiding your client and suggesting possible valid
> transitions with each step client performs.
Yup.
> This gives opportunities to extend your application protocol without
> changing your domain model. Which you would have to do if you expose
> your aggregate roots as Rickard suggest. E.G. you can add a possibility
> for clients to complete a survey for a discount without changing your
> existing model. And you do it unobtrusively, clients that know how to
> use that capability will use it without breaking old clients.
My experience is much simpler than that: if you expose the domain model
there is no way to guide the client, since there is no "path" to be
followed. If you expose usecases, there is a guide, and doing the
linking thing becomes trivial. And writing clients becomes REALLY easy!
> How about reading couple of books about REST before discussing whether
> to apply it without knowing what it is and what it's for:
>
> http://www.amazon.com/Restful-Web-Services-Leonard-Richardson/dp/0596529260
> http://www.amazon.com/REST-Practice-Hypermedia-Systems-Architecture/dp/0596805829/ref=sr_1_1?s=books&ie=UTF8&qid=1316512893&sr=1-1
I would also suggest the REST thesis itself. Skip to ch5 if you are
short on time:
http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
I started my project doing the "expose your domain model" thing. It was
VERY painful. The more I changed to what Roy is talking about, the
simpler my server and client became. Stop thinking about a REST API as a
"service facade", and instead think of it as a simplistic website, and
it becomes much easier to get it right.
/Rickard
The point I'm trying to make is that exposing these domain level objects
as REST resources is the wrong thing to do. Expose usecases.
Now, I have NO IDEA what your usecases are, and quite possibly you don't
know it either (remarkably common problem), but let me just guess what
could be usecases for orders:
1) Placing an Order in a shop
2) Servicing an Order in a warehouse
3) Tracking your own Orders online
4) Displaying customers Orders in a callcenter
5) Performing analytics of Orders
etc.
All these are separate usecases, all of which require *SEPARATE* REST
API's. If you expose your domain model, which pretty much all bloggers
suggest and which pretty much all responses in this thread suggest, you
are in for massive amounts of pain when real life hits you in the butt.
You will have no way to guide the clients through the above usecases by
means of following links, and in effect all the usecase logic will be in
various client code, with lots of if statements and whatnot. I've seen
this before, and headache follows, always.
Based on the responses so far I seriously doubt that many here have
actually read the REST thesis, and I seriously doubt that many here have
actually built REST API's based on the suggestions posed, because the
pain involved with the results of said suggestions are just too obvious,
in real life.
To know what your usecases are requires understanding the UI more than
understanding the domain model. When you understand the UI, and the
usecases it contains, then you create your REST API from there, and then
map that to the underlying domain model. Not the other way round.
Then everything becomes simple, logical, and having many clients to the
same app is trivial rather than cumbersome.
/Rickard
I actually tried to do the AR as resources thing. It was very bad because we had to embed many UI rules in the domain and there was no easy way to not break (heavily) the UI when we refactored the domain. In REST you sometimes need resoures coarser than your domain entities, not having these and relying on object navigation forces your domain to be anemic and data-structure oriented. Having resources too fine grained makes your API too chatty which is very bad in REST.
Exactly. You need the usecases as the mediator between the UI and the
domain, and when you expose the domain you either have to put usecases
in the domain (which doesn't work), or you have to put the usecases in
the UI, which leads to chatty and inconsistent usecase handling.
> In
> REST you sometimes need resoures coarser than your domain entities, not
> having these and relying on object navigation forces your domain to be
> anemic and data-structure oriented.
Exactly. The usecases provides that middle ground that does this, and in
a consistent way no matter which client uses it.
> Having resources too fine grained
> makes your API too chatty which is very bad in REST.
Exactly. I have seen cases where one UI screen makes hundreds of REST
calls, to get attributes from various domain objects. It is ok on a dev
machine (localhost access), but not so ok in a real production
environment. Both latency and scalability goes down the drain.
And these are all things that I have seen in my own and others'
projects, every time, which leads me to question whether the other
respondents in this thread has actually 1) read the REST thesis and 2)
tried this in real life. Same goes for bloggers who suggest that
exposing the domain model is a good way to do REST.
The hardest part about exposing usecases is that you have to actually
know what they are. But that's a GOOD problem, and finding that out is
in line with DDD in general, and understanding the business problems as
well.
/Rickard
"Web architects must understand that resources are just consistent mappings from an identifier to some set of views on server-side state. If one view doesn’t suit your needs, then feel free to create a different resource that provides a better view (for any definition of “better”). These views need not have anything to do with how the information is stored on the server, or even what kind of state it ultimately reflects. It just needs to be understandable (and actionable) by the recipient."
http://roy.gbiv.com/untangled/2008/paper-tigers-and-hidden-dragons
This is sort of contrary to the CQRS + DDD ideas. As many have already
stated, you should *not* expose your domain entities as resources. Make
up are API based on commands and queries which result from your business
case, not your mental domain model.
Talk to your business, define user cases and use DDD. Or else, if the
problem domain is shallow enough, forget about DDD and CQRS altogether.
For many applications, this is just too heavy a toolset.
Phil
Yup. And you might as well skip the "domain" entirely, and go straight
to the database, if it has a "REST" API. I don't know a single database
that actually has a REST API though, although many claim to have.
/Rickard
Ok, what is the usecase?
/Rickard
That is not a usecase. Read up on usecases, and try again.
/Rickard
The trading service reads nicely as a CQRS interface, so I would
translate it into a REST interface along the lines of the previous
discussion.
However, I want to point out that this is purely an API description and
I take the methods to be your use cases...
command resources: (PUT, possibly POST, maybe GET)
.../Trading/OpenNewAccount/<cid>
.../Trading/RegisterExternalAccount/<cid>
.../Trading/TransferCash/<cid>
.../Trading/PlaceOrder/<cid>
.../Trading/Order/<id>/CancelOrder/<cid>
If the API is larger and the various account IDs only refer to
non-external accounts, you might want to group commands as resources
below the account concept, e.g. .../Trading/Account/<id>/PlaceOrder/<cid>
queries operate on collections (GET):
.../Trading/Accounts?queryparams
and
.../Trading/Account/Summary/<id>
.../Trading/Account/Information/<id>
etc.
where the response of the former would contain links to the latter.
And the latter would contain links to available commands in which that
account may participate.
You can even have command resources GETable and return empty command
objects to be filled (think autogenerating UI here)...
Personally I still like PUTing commands and be able to get them to
retrieve status info. Especially for a trading system as orders are
idempotent by API design in that case.
So I still stand by my original and very first answer in this thread:
CQRS and REST may play together nicely, but the commands (read use
cases) are the resources, not the entities of the domain behind it.
But I also stand by my last post: if the domain does not contain
complicated rules (and collaboration), DDD + CQRS is maybe not needed at
all here. As from the API interface snippet, it is still hard to judge
the extent of the model behind it and its volatility.
And of course, this is purely IMHO, we have already seen in this thread
that there are a number of different perspectives, mine is way more CQRS
than REST....
Cheers
Phil
Here's the thing. I can talk about usecases until I'm blue in the face,
and it won't help you a thing if you don't actually know what a usecase
is. So until you know what a usecase is, I can't actually help you, even
if I want to (and I do). See my point?
Let's make it easier: if you were to design a website for users to
access the service, what would it look like? There's no copying of
URL's, creating URL's manually or POST-ing this or that allowed. You can
do is generate HTML, forms, and links, which the user can interpret and
use. That's all. Do that, then remove all styling, add "rel" attributes
on all links and forms, and voila, you have a REST API that is
usecase-oriented.
/Rickard
That is the sad state of things, yeah.
> So why don't we
> all work as a team to define use cases the way you like to see them and
> then define a REST API for them. I will be fully supportive.
Me too! See my previous response for a start. If you develop a
minimalistic website as if it was intended for a human, where all the
human is supposed to do is go to a given URL and then follow links and
fill in forms, AND ONLY THAT, that is the best way to start thinking
about it. Forget RPC and WebServices, and all that, and think of it
simply as a very very bare website. That is the easiest way to start.
Then replace the human with a system, or something that renders that
website as a rich client (Swing, Flash, AJAX, etc.), and you're good to go.
A REST API is defined, contractually, not by how the URL's are
constructed, but rather by the mediatype and (if you use XHTML or any
link-friendly mediatype) the welldefined "rel" names on links. Clients
should NEVER bother with how URL's are constructed, if you are doing
REST, since they are not allowed to use any URL they have not received
previously as a link or form.
/Rickard
Actually, now that I think about it, there are tons of examples out
there. We just normally call them "websites", and not REST APIs, but
most of them comply just fine with the REST constraints. It's when we
try to do this for "machines" that it gets all bungled up, and our
experience with services and method calls get in the way.
/Rickard
Awesome! So, given that you can now identify the usecases, and build the
REST API accordingly.
Here's a start:
GET / ->
XHTML with links that can have "rel" set to one of:
"signup"
"login"
GET link with "signup" rel ->
XHTML with form for signup info. Fill in form and submit (with whatever
method the form has as "method" attribute).
GET link with "login" rel ->
XHTML with form for login. Fill in form and submit. Follow redirects.
GET on URL retrieved from redirect ->
XHTML with links that can have "rel" set to one of:
"accounts","positions", etc.
GET link with "transfer" rel ->
XHTML with form for transfer. Fields for from-account and to-account
will have list of available options for accounts. Fill in, select
accounts supplied in form, and submit. Follow redirects.
And so on.. this is the definition of the REST API that you share with
your customers, if you want them to be able to use your service with
their own client. The underlying design of the REST API, i.e. the URL
structure, are details that are not part of the contract. Do whatever
makes sense for you. The REST API contract are the names of the "rel"
attributes, the mediatypes (e.g. XHTML), and HTTP itself.
Is that more clear?
/Rickard
What this means is that a REST *API* is defined (when done properly) by
the hypermedia choice and well-defined "rel" link attributes, not by the
URL structure and when to use GET/POST/PUT. The REST API *design and
implementation* consists of the URL structure and choice of methods, but
because that is technically not part of the published API you can change
it at any point in time. Since most REST "API"s consider the URL
structure to be part of the API contract, they have a problem in that it
becomes hard to change. By not making the URL structure part of the
formal contract this gives you a lot of freedom in how to change that as
the system evolves, without breaking any clients (since they are not
allowed to make assumptions about URL's and methods).
One of the key things here is that on the client-side it is advisable to
provide some kind of library that the application developers use, and
which enforce this, i.e. application developers can never say "I want to
call this URL", and instead they are only provided a list of links which
they can choose from, and the library helps with picking the right
method to use to invoke it, rather than the application developer
explicitly doing a POST or a PUT.
So for example, initially you may choose to use POST for some action,
and later redesign it to allow PUT, and the application clients are not
impacted at all, since they never decided explicitly what method to use
anyway. They are just submitting forms, with whatever the form says
should be used as method.
In the human world the "library" we use for this is the browser. It
helps us by providing a rendering of the links and forms, which we
interact with, rather than manually changing the URL in the browser to
access various parts of an application. It needs to be the same for
machine users of a REST API. Then writing apps becomes easy, you need to
worry less about versioning, and the app becomes more scalable as a
result, since a minimal number of HTTP calls are made.
/Rickard
A clarification:
On Sep 24, 2011 2:13 AM, "Naresh Bhatia" <bha...@comcast.net> wrote:
>
> Rickard,
>
> Still digesting! In fact quite confused as you will see from my questions below.
>
> Here's what I have so far - I have started creating a "bare" web site as you suggested - using links with "rel" attributes and forms for submitting data. See http://archfirst.googlecode.com/svn/trunk/docs/bullsfirst/rest-prototype/index.html. For example, this page has a link to open an account:
>
> <a rel="openAccount" href="open-account.html">Open an Account</a>
>
> and a form to log in:
>
> <form id="login" action="accounts.html">
> Username: <input type="text" name="username" /><br/>
> Password: <input type="password" name="password" /><br/>
> <input type="submit" value="Login" />
> </form>
>
> So far so good. But where to go from here? My fundamental question is are we doing this to identify what goes in the REST API or is this the REST API itself. If this indeed is the REST API, I feel that we have gone well beyond HTTP and starting to rely on HTML. Also it is starting to look like a presentation layer. So let me break this down to some detailed questions.
> Is the openAccount link shown above relevant to the REST API? Isn't it just navigation that is relevant to the front-end only. Other pages, such as accounts.html, have even more navigational links (e.g. one for each tab). In a smart front-end, clicking on these links is completely internal to the app and does not require calling any REST APIs.
In REST the client (your smart front end) don’t control the urls or the hypermedia contents so it may not know them in advance, only the mime types descriptions and rels used.
> Is the login form shown above relevant to the REST API? A smart front-end does not have to literally grab such a form from the server, it just knows that this information is needed by the server API to login. The point I am trying to make is that a human user can probably adjust to changes in a form on an HTML page, but a program using a REST API can't. For example, if the server suddenly added a field called Device Id to this form, a client program would have no idea what to do with it.
Talking about login, it's usually better to use auth headers instead, so the server only asks for them when required.
Now suppose we deploy a REST app and there's a form reachable to a client with two fields. These are described in the mime type for the representation the form is in. If we add a new field the server needs to deal with this api evolution. It can version the representation and support both (perhaps the action url is different and we have different controllrs responding, one expecting two fields and one expecting three) provide the form with a default value for the new field, refuse to answer the POST without the new field, refuse to serve the old version of the mime type (if we versioned the mime type), 404 the url used to GET the form (if we version using urls). In REST the server controls the API evolution. The client only follows the links and acts on what it understands. Of course a client needs to be programmed to deal with a specific form or rel, but it may safely ignore whatever other forms or rels it doesn't understand and still work if the server don't break the old use cases.
> The only other interpretation of the link and the form above I can think of is that they help us identify the use cases and the data needed to spec out an API, but they are not the API in themselves.
> If I wanted to use JSON requests and responses where and how would I specify them?
Who is "I" in this sentence? This is supposed to be part of conneg (i.e. content negotiation), the server can add and enctype to the form with the expected Content-Type.
> For the accounts page, the server needs to send a list of accounts including flags indicating whether each account is editable or not. Using this information, the front-end can easily create a presentation. Specifically, a link for navigating to a detail page (positions) and another to navigate to an edit page. Again, I see these links as purely navigational within the client and not something that needs to come through REST responses.
The server knows the account is editable so it provides the valid transitions (i.e. links or forms). The front end just displays them, without having to check if the accounts are editable.
Try to think REST as a conversation, the server responds with the next valid steps in the conversation.
Yes, and that is a good thing, although even better would be to use
XHTML, since it is easier to parse as it is proper XML. When doing REST
a key decision is which hypermedia to use. You can XHTML, or a custom
JSON dialect with added links, or Atom. As long as you have support for
links, it is a good start.
> Also it is starting
> to look like a presentation layer.
It is the application layer. In the presentation layer you could
aggregate the usecases exposed by the application layer, so in a proper
presentation layer you might combine several usecases in one screen. The
above would just represent one of those usecases.
> So let me break this down to some
> detailed questions.
>
> * Is the openAccount link shown above relevant to the REST API? Isn't
> it just navigation that is relevant to the front-end only. Other
> pages, such as accounts.html, have even more navigational links
> (e.g. one for each tab). In a smart front-end, clicking on these
> links is completely internal to the app and does not require calling
> any REST APIs.
Clients are not allowed to construct any URL's, so without links, the
client cannot do anything beyond going to the initial URL. It is
"navigation" only in the sense that it shows the structure of the
usecases. In presentation layer navigation you have navigation for
presentation purposes, which might be different. In a simplistic client
there might be a 1-1 mapping, but that is only the simplest case.
> * Is the login form shown above relevant to the REST API? A smart
> front-end does not have to literally grab such a form from the
> server, it just knows that this information is needed by the server
> API to login. The point I am trying to make is that a human user can
> probably adjust to changes in a form on an HTML page, but a program
> using a REST API can't. For example, if the server suddenly added a
> field called Device Id to this form, a client program would have no
> idea what to do with it.
The difference is that if you, for example, add fields to forms, then if
those fields provide defaults, then even old clients that are not yet
updated will still work. If you don't GET the form first, with the
defaults, old clients will break. So doing it this way will help with
versioning.
> * The only other interpretation of the link and the form above I can
> think of is that they help us identify the use cases and the data
> needed to spec out an API, but they are not the API in themselves.
The "rel" names are indeed part of the API, as they form the formal
contract you have with clients. URL's are not a part of the API, at all.
In a proper REST API you should be able to change URL's at any point in
time, with no clients breaking.
> * If I wanted to use JSON requests and responses where and how would I
> specify them?
You would have to specify a dialect of JSON which details how links are
represented. Once you have that you're good to go. This is, in fact,
what I'm doing myself, rather than using XHTML.
> * For the accounts page, the server needs to send a list of accounts
> including flags indicating whether each account is editable or not.
> Using this information, the front-end can easily create a
> presentation. Specifically, a link for navigating to a detail page
> (positions) and another to navigate to an edit page. Again, I see
> these links as purely navigational within the client and not
> something that needs to come through REST responses.
Again, without the server telling the client where the accounts are, the
client would have NO IDEA where those URL's are. My favourite solution
for table-ish data is the Google Data Table API, where you can
effectively have a negotiation between what columns the server offers,
and what the client wants.
I use this, for example, to support both Swing clients and mobile
devices. The Swing client does "select *" whereas the mobile client
would typically do something like "select description, href" to get just
the info needed for a list of links, which when used would provide the
details ("select *").
> I guess I am having trouble separating presentation stuff from data when
> using this approach. What am I missing?
The problem with the SOAPy approach is that you put the application
layer and usecases in the client, so the client is "too smart". Once you
expose usecases from the application layer in the REST API, all that
logic is encoded on the server instead of the client, and the client
then becomes really thin. It then becomes VERY EASY to do multiple
clients, for multiple platforms or devices, which behave exactly the
same way. This is very hard to do if you expose too low-level things,
like the domain model.
I'm wondering: have you read the REST thesis? If not, I think now would
be a good time to do so... it explains a lot of these things, and why
you want to do this in the first place.
regards, Rickard
i, for one, seem to recall reading it... or trying to read it. it is
great, but it is bad. i think your posts, Rickard, on hateoas helped
me understand it better! :-)
It depends. Sometimes you may want to use auth headers instead, and that
would be perfectly ok (I do it), but sometimes you may want to have an
explicit login if you need to generate some token instead, and also if
only that page should be using HTTPS. Both are ok, I think. It also
depends on whether the login requires more than just user/password. A
device id is one example, or maybe a strong authentication password from
some hardware thingy. Then headers might not be enough.
> Now suppose we deploy a REST app and there's a form reachable to a
> client with two fields. These are described in the mime type for the
> representation the form is in. If we add a new field the server needs
> to deal with this api evolution. It can version the representation and
> support both (perhaps the action url is different and we have different
> controllrs responding, one expecting two fields and one expecting
> three) provide the form with a default value for the new field, refuse
> to answer the POST without the new field, refuse to serve the old
> version of the mime type (if we versioned the mime type), 404 the url
> used to GET the form (if we version using urls). In REST the server
> controls the API evolution. The client only follows the links and acts
> on what it understands. Of course a client needs to be programmed to
> deal with a specific form or rel, but it may safely ignore whatever
> other forms or rels it doesn't understand and still work if the server
> don't break the old use cases.
Exactly. One problem with current REST API approaches also, from a
client programming perspective, is that they are too imperative, as in
"first do this, then do this, then that". Considering above I think REST
clients need to be able to support more thinking along the lines of "if
this, then that. If this, then that" etc. i.e. more declarative. Then it
becomes easier for the client to react to such changes. So, the problem
is not only that REST API's are screwed up, but also the client side.
/Rickard
It will be RESTful if you follow the REST constraints. If you don't know
what the REST constraints are, and why they are there, it is VERY
DIFFICULT indeed to do REST.
/Rickard
Here's how I structure my URL's: anything ending with "/" represents a
usecase. In there you will have queries and commands, e.g. "/index"
query and "/markspam" command. If I have this for the inbox:
"/index"
which returns a Google Data Table that lists the emails, and then the
client selects one email:
/1234/index
-> info about email + link to /1234/markspam
When the client POSTS to "markspam" the result could either be a list of
generated events which the client can react to (this is what I do), or
you could return a redirect to /1234/index to indicate that a refresh
would be "good to do at this point". This is without CQRS/EventSourcing.
However, a client may be showing both the Inbox full list, as well as
the individual email, so how to know that both needs refresh? This is
why I return the list of generated events as command invocation result,
and which is why I think EventSourcing really works well with REST APIs.
Clients who understand these can then on their own figure out what to
refresh. In my client I simply notify all active views of what events
have just been created, so any view might react to the events.
/Rickard
I have been wondering about whether and to what extent publish domain
events. Do you just send event type and aggregate ID or actual events
including properties? My events can at times contain sensitive
information that I do not really want to be broadcasted.
So for the moment I just provide the aggregate IDs which were touched
plus responsible user ID. My clients act on detecting a known aggregate
ID with refreshing their models, or warning the user of possible
concurrency if the event originated from another session.
I thought about either providing more verbose client-side events
aggregated out of domain events, or annotate event properties with
privacy information and strip down to the acceptable subset when
serialising, but haven't really tried either in full. Do you have any
suggestions?
Cheers
Phil
First of all /index is not an event, but as you say, it's a query.
What would happen is that the views get notified with the events that
are returned, from any command invocation, and whenever they see
something they're interested in (whether it was "that" view which caused
it is unimportant), they can update appropriately.
> Exposing events as resources won't work either as handling the same
> event is different per each view.
Yup.
/Rickard
I send the whole thing, but the client views actually never use that.
They only look at what usecase triggered it, the name of the event, and
the id of the affected entity. I have so far never used the actual event
payload. So that would probably be optional, especially if it's
sensitive information and you don't do HTTPS encryption of the connection.
> My events can at times contain sensitive
> information that I do not really want to be broadcasted.
> So for the moment I just provide the aggregate IDs which were touched
> plus responsible user ID. My clients act on detecting a known aggregate
> ID with refreshing their models, or warning the user of possible
> concurrency if the event originated from another session.
> I thought about either providing more verbose client-side events
> aggregated out of domain events, or annotate event properties with
> privacy information and strip down to the acceptable subset when
> serialising, but haven't really tried either in full. Do you have any
> suggestions?
Right, one way is to "aggregate" the events on the serverside into
client refresh events. I've seen systems do that. To me that pushes too
much understanding of the client to the server, but if you only have one
client, then sure.
/Rickard
Right, so this is for synchronous command processing. My commands ALWAYS
only touch the domain model, so they are relatively quick to process.
Anything more complicated than that, let's say sending an email, is done
by listeners on the events, so that retries and such can be done.
For example, I have a domain model for basically a discussion thread.
The command would post a new message on the discussion object model,
which would generate events that a service then reads and generates the
associated emails. So the posting itself is fast, while the service
reaction to it might be slow. Which is fine.
/Rickard
Right, so this is for synchronous command processing. My commands ALWAYS only touch the domain model, so they are relatively quick to process. Anything more complicated than that, let's say sending an email, is done by listeners on the events, so that retries and such can be done.
For example, I have a domain model for basically a discussion thread. The command would post a new message on the discussion object model, which would generate events that a service then reads and generates the associated emails. So the posting itself is fast, while the service reaction to it might be slow. Which is fine.
Always! This industry is extreme in that sense, because pretty much
anything comes down to "it depends".
For example, if you don't need the constraints that REST adds, then..
don't do it. Do something else with HTTP that is not REST (like, pretty
much everyone)! But if you like the constraints, because you like the
tradeoffs that this implies (pros AND cons), then go for it!
As an example, to me it makes no sense whatsoever for a database to have
a REST API. HTTP API, absolutely, but REST? Why? The constraints that
are imposed in REST doesn't seem to fit with the requirements of a
database. And, if you look closely (almost) none of the databases that
say they have a REST API actually do. There are lovely HTTP API's
though, which don't follow the REST constraints. So naming the damn
thing they're doing correctly is the biggest problem, as far as I'm
concerned.
/Rickard
Or combine with a WebSocket that streams them back asynchronously. So
many options... it all depends...
/Rickard
There can be queuing. after POST you can respond with 202 accepted and provide location header where client can pull for result.You can also use ATOM PUB to post to queues and pull on them.
You could do "commands as resources" and still return 202 as the result.
Should be ok.
/Rickard
The difference is that if you, for example, add fields to forms, then if those fields provide defaults, then even old clients that are not yet updated will still work.
Again, without the server telling the client where the accounts are, the client would have NO IDEA where those URL's are.
The problem with the SOAPy approach is that you put the application layer and usecases in the client, so the client is "too smart". Once you expose usecases from the application layer in the REST API, all that logic is encoded on the server instead of the client
The hardest part about exposing usecases is that you have to actually know what they are. But that's a GOOD problem, and finding that out is in line with DDD in general, and understanding the business problems as well.
To me there is a big difference here. First of all, I can create a link to the first, but no to the second, thus informing the client about the possible next states.
Also, I can do a GET on the first and either get 200 (=it's ok to perform the command) or 404 (=it's not ok to perform the command),
which is very important from a UI point of view. Never allow UI's to "try" commands that are sure to fail. The first variant helps, whereas the second don't.
This doesn't need to be sync at all. The client can send one way commands and subscribe to the event stream. Also CQRS can be sync or async.
Nuno, check this presentation and see if it makes the "why" clearer:
http://www.slideshare.net/trilancer/why-hateoas-1547275
I would tend to agree with the assessment here in the delete case. Create as well.. it is more interresting with updates
What REST constraint does it violate?
> E.G. client can issue DELETE to order resource, server interprets it as
> "cancel order" users intention. So it does not map to CancelOrder resource.
What if you need to provide a comment when you cancel an order?
How do you know that DELETE on order is "cancel" rather than "finished
handling" or "delivered" or "processed"?
> As for exposing domain as resources: If you can do it you're probably
> not really capturing and automating your domain. Resources form a layer
> for interactions, application protocol. Same as you application layer or
> service layer isn't your domain.
That is why you should expose your usecases as REST resources. The
usecases are your commands and queries.
/Rickard
That has nothing to do with REST as such I'm afraid. It only shows that
there is more understanding to be done for how to implement it properly,
and so far, with the amount of cluelessness about REST that is around
(your posts are a good example), it would be surprising to see anything
else.
>> Again, without the server telling the client where the accounts are,
>> the client would have NO IDEA where those URL's are.
>
> Why?
Because that would imply that there is an out-of-band contract for how
to create those URLs, which means that if the URLs change, the client
breaks, which is one of the problems that REST fixes by relying on
hypermedia to discover those URLs.
>> The problem with the SOAPy approach is that you put the application
>> layer and usecases in the client, so the client is "too smart". Once
>> you expose usecases from the application layer in the REST API, all
>> that logic is encoded on the server instead of the client
>
> Most our Web Apps only do field validation on the client side. My
> problem is not really about constructing URL, I guess.
But if you have a client that "knows" how to construct URLs, that means
if you change them, the clients break. With REST, where hypermedia is
used to discover URLs, URLs are considered an internal implementation
detail that can change at any time. Remember that changing URLs does not
necessarily mean that the path changes. It could just as well be that
the server changes. Let's say you have a main server for the bulk of the
API, but a particular server for one particular query that is heavy to
perform and is used a lot. With REST, where the URLs are discoverable,
you can easily change the server layout on the fly to handle this. With
clients "knowing" how to construct URLs, you are in trouble, and have to
do other tricks to get around it.
>> The hardest part about exposing usecases is that you have to actually
>> know what they are. But that's a GOOD problem, and finding that out is
>> in line with DDD in general, and understanding the business problems
>> as well.
>
> Once you know what they are, we don't need REST.
REST just makes it easier to implement them, since the outcome of
understanding the problem are usecases (commands and queries), and REST
is really good at dealing with that, if you expose the commands and
queries as first-class resources.
>> To me there is a big difference here. First of all, I can create a
>> link to the first, but no to the second, thus informing the client
>> about the possible next states.
>
> Isn't that what the Controller in MVC does? I mean, the Controller maps
> the use case to the Domain API. If the View representation can be
> anything. In order words it serves execution paths base on the domain
> state. Calculating all possible next states is hardly a deterministic
> endeavor.
MVC is used on the client. If you want the Controller to make these
decisions then 1) the controller needs to get that domain state from the
server, which means you are exposing domain state through REST (or
WebServices, or CORBA, or whatever), which leads to chatty interfaces 2)
you have the risk of multiple clients with different controllers having
different rules for the application state and 3) doing authorization
properly will be VERY HARD since most auth rules I've worked with
require domain state, so you need to expose that to the client which
then says "oh this user does not have permission to do this, oops" (but
then the state is already exposed).
You are just getting yourself into a world of pain. Been there, done
that, moving on.
>> Also, I can do a GET on the first and either get 200 (=it's ok to
>> perform the command) or 404 (=it's not ok to perform the command),
>
> Why is that an advantage of REST only?
Well, SOAP, for example, can't do it. You have to introduce your own
services on top of SOAP to be able to ask the server what you can do.
But then again, you said that such decisions are made on the client by
the Controller, so you don't see the problem. But then you will have the
1-2-3 problems above.
>> which is very important from a UI point of view. Never allow UI's to
>> "try" commands that are sure to fail. The first variant helps, whereas
>> the second don't.
>
> How does it help?
When the server expose usecases (commands and queries), the client can
ask the server at any time "what can I do now" and the response comes in
the form of either 200/404 if you "try the command", but more
realistically, it will come in the form of hypermedia with links that
say "given the current application state, this is what you can do next".
The existence of a link with a given rel is then used to enable/disable
operations in the UI. For example, if an email has already been marked
as spam, then when you get the hypermedia for the email (in the previous
example) you will not get a link with rel "markspam" and so you can hide
or disable the "markspam" button.
/Rickard
> E.G. client can issue DELETE to order resource, server interprets it as
> "cancel order" users intention. So it does not map to CancelOrder resource.
That has nothing to do with REST as such I'm afraid.
It only shows that there is more understanding to be done for how to implement it properly, and so far, with the amount of cluelessness about REST that is around (your posts are a good example), it would be surprising to see anything else.
Because that would imply that there is an out-of-band contract for how to create those URLs, which means that if the URLs change, the client breaks, which is one of the problems that REST fixes by relying on hypermedia to discover those URLs.
But if you have a client that "knows" how to construct URLs, that means if you change them, the clients break.
REST just makes it easier to implement them, since the outcome of understanding the problem are usecases (commands and queries), and REST is really good at dealing with that, if you expose the commands and queries as first-class resources.
MVC is used on the client. If you want the Controller
Been there, done that, moving on.
When the server expose usecases (commands and queries), the client can ask the server at any time "what can I do now" and the response comes in the form of either 200/404 if you "try the command", but more realistically, it will come in the form of hypermedia with links that say "given the current application state, this is what you can do next".
How does it violate the uniform interface? I don't see that...
> > E.G. client can issue DELETE to order resource, server interprets it as
> > "cancel order" users intention. So it does not map to CancelOrder
> resource.
>
> What if you need to provide a comment when you cancel an order?
>
> You might wanna create CanceledOrders resource and have client pot
> orders to it with comments and whatever else you need.
So you will have one resource for listing cancelled orders and doing the
actual cancelling? And how does the client get the link to do that?
> How do you know that DELETE on order is "cancel" rather than "finished
> handling" or "delivered" or "processed"?
>
> Depends on a context of an app
And how do you communicate that context?
> > As for exposing domain as resources: If you can do it you're probably
> > not really capturing and automating your domain. Resources form a layer
> > for interactions, application protocol. Same as you application layer or
> > service layer isn't your domain.
>
> That is why you should expose your usecases as REST resources. The
> usecases are your commands and queries.
>
> bolox
Why?
/Rickard
> > E.G. client can issue DELETE to order resource, server interprets it as
> > "cancel order" users intention. So it does not map to CancelOrder
> resource.
>
> What if you need to provide a comment when you cancel an order?
>
> You might wanna create CanceledOrders resource and have client pot
> orders to it with comments and whatever else you need.
> How do you know that DELETE on order is "cancel" rather than "finished
> handling" or "delivered" or "processed"?
>
> Depends on a context of an app
> > As for exposing domain as resources: If you can do it you're probably
> > not really capturing and automating your domain. Resources form a layer
> > for interactions, application protocol. Same as you application layer or
> > service layer isn't your domain.
>
> That is why you should expose your usecases as REST resources. The
> usecases are your commands and queries.
>
> bolox
Sharas
Since CancelOrder is an endpoint, not a resource, you cannot manipulate it with uniform interface, e.g can you query CancelOrder? Is that even meaningful? That's right, it's not, because CancelOrder is an endpoint not a resource. You will be better off with SOAP and RPC tunneling with that mindset.