CQRS and REST: the perfect match

In many of my applications, the UI and API gravitate towards task-oriented UIs. Instead of “editing an invoice”, I “approve an invoice”, with specialized models, behaviors and screens just for accomplishing that task. But what happens when we move from a server-side application to one more distributed, to be accessed via an API?

In a previous post, I talked about the difference between entities, resources, and representations. It turns out that by removing the constraint around entities and resources, it opens the door to REST APIs that more closely match how we’d build the UI if it were a completely server-side application.

With a server side application, taking the example of invoices, I’d likely have a page to view invoices:

GET /invoices

This page would return the table of invoices, with links to view invoice details (or perhaps buttons to approve them). If I viewed invoice details, I’d click a link to view a page of invoice details:

GET /invoices/684

Because I prefer task-based UIs, this page would include links to specific activities you could request to perform. You might have an Approve link, a Deny link, comments, modifications etc. All of these are different actions one could take with an invoice. To approve an invoice, I’d click the link to see a page or modal:

GET /invoices/684/approve

The URLs aren’t important here, I could be on some crazy CMS that makes my URLs “GET /fizzbuzzcms/action.aspx?actionName=approve&entityId=684”, the important thing is it’s a distinct URL, therefore a distinct resource and a specific representation.

To actually approve the invoice, I fill in some information (perhaps some comments or something) and click “Approve” to submit the form:

POST /invoices/684/approve

The server will examine my form post, validate it, authorize the action, and if successful, will return a 3xx response:

HTTP/1.1 303 See Other
Location: /invoices/684

The POST, instead of creating a new resource, returned back with a response of “yeah I got it, see this other resource over here”. This is called the “Post-Redirect-Get” pattern. And it’s REST.

CQRS and REST

Not surprisingly, we can model our REST API exactly as we did our HTML-based web app. Though technically, our web app was already RESTful, it just served HTML as its representation.

Back to our API, let’s design a CQRS-centric set of resources. First, the collection resource:

GET /invoices

HTTP/1.1 200 OK
[
  {
    "id": 684,
    "invoiceNumber": "38042-L-275-684",
    "customerName": "Jon Smith",
    "orderTotal": 58.85,
    "href": "/invoices/684"
  },
  {
    "id": 688,
    "invoiceNumber": "33453-L-275-688",
    "customerName": "Maggie Smith",
    "orderTotal": 863.88,
    "href": "/invoices/688"
  }
]

I’m intentionally not using any established media type, just to illustrate the basics. No HAL or Siren or JSON-API etc.

Just like the HTML page, my collection resource could join in 20 tables to build out this representation, since we’ve already established there’s no connection between entities/tables and resources.

In my client, I can then follow the link to see more details about the invoice (or, alternatively, included links directly to actions). Following the details link:

GET /invoices/684

HTTP/1.1 200 OK
{
  "id": 684,
  "invoiceNumber": "38042-L-275-684",
  "customerName": "Jon Smith",
  "orderTotal": 58.85,
  "shippingAddress": "123 Anywhere"
  "lineItems": [ ]
  "href": "/invoices/684",
  "links": [
    { "rel": "approve", "prompt": "Approve", "href": "invoices/684/approve" },
    { "rel": "reject", "prompt": "Reject", "href": "invoices/684/reject" }
  ]
}

I now include links to additional resources, which in the CQRS world, those additional resources are commands. And just like our HTML version of things, these resources can return hypermedia controls, or, in the case of a modal dialog, I could have embedded the hypermedia controls inside the original response. Let’s go with the non-modal example:

GET /invoices/684/approve

HTTP/1.1 200 OK
{
  "invoiceNumber": "38042-L-275-684",
  "customerName": "Jon Smith",
  "orderTotal": 58.85,
  "href": "/invoices/684/approve",
  "fields": [
    { "type": "textarea", "optional": true, "name": "comments" }
  ],
  "prompt": "Approve"
}

In my command resource, I include enough information to instruct clients how to build a response (given they have SOME knowledge of our protocol). I even include some display information, as I would have in my HTML version. I have an array of fields, only one in my case, with enough information to instruct something to render it if necessary. I could then POST information up, perhaps with my JSON structure or form encoded if I liked, then get a response:

POST /invoices/684/approve
comments=I love lamp

HTTP/1.1 303 See Other
Location: /invoices/684

Or, I could have my command return an immediate response and have its own data, because maybe approving an invoice kicks off its own workflow:

POST /invoices/684/approve
comments=I love lamp

HTTP/1.1 201 Created
Location: /invoices/684/approve/3506
{
  "id": 3506,
  "href": "/invoices/684/approve/3506",
  "status": "pending"
}

In that example I could follow the location or the body to the approve resource. Or maybe this is an asynchronous command, and approval acceptance doesn’t happen immediately and I want to model that explicitly:

POST /invoices/684/approve
comments=I love lamp

HTTP/1.1 202 Accepted
Location: /invoices/684/approve/3506
Retry-After: 120

I’ve received your approval request, and I’ve accepted it, but it’s not created yet so try this URL after 2 minutes. Or maybe approval is its own dedicated resource under an invoice, therefore I can only have one approval at a time, and my operation is idempotent. Then I can use PUT:

PUT /invoices/684/approve
comments=I love lamp

HTTP/1.1 201 Created
Location: /invoices/684/approve

If I do this, my resource is stored in that URL so I can then do a GET on that URL to see the status of the approval, and an invoice only gets one approval. Remember, PUT is idempotent and I’m operating under the resource identified by the URL. So PUT is only reserved for when the client can apply the request to that resource, not to some other one.

In a nutshell, because I can create a CQRS application with plain HTML, it’s trivial to create a CQRS-based REST API. All I need to do is follow the same design guidelines on responses, pay attention to the HTTP protocol semantics, and I’ve created an API that’s both RESTful and CQRSful.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in CQRS, DomainDrivenDesign, Microservices, REST. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Kurt Dowswell

    Nice post! Very CQRSful indeed :) I really like the links and actions you provide in the response objects. Gave me some ideas for sure!

  • Miguel Hasse

    what is an even better match, is http://www.jsonrpc.org

    • jbogard

      That’s RPC. I wouldn’t mind that for closed systems for a SOAP replacement, but for decoupling I use REST.

      Though to be honest I haven’t really had a use for SOAP/RPC in a while

      • You expect a reply synchronously, how is it decoupling?

        • jbogard

          Well, HTTP will add *some* level of temporal coupling. I’m more referring to the “HTTP is not RPC” decoupling that Fielding talked about.

          Though if you do async commands via 202 Accepted, it means the reply is “yep I got it, and the work is later” vs. “I am done with the work and here is the result”.

          • I might have misunderstood you. I actually like the idea providing a response with GET to further fetch the command processing status, we can have a process or downstream event processing, by querying this URL we can get a status update easier than using real-time events push from the server.

          • jbogard

            Yep! This is the typical pattern I like when communicating across bounded contexts. Internal to one, not so much because the tradeoff in complexity at that point isn’t worth it.

            I ESPECIALLY do this as integration points to external providers. They want 100% uptime and zero latency and I say fine, I can have super fast latency provided I do almost zero actual work :)

      • Roger Alsing

        How is your example not RPC also as you are using verbs like “approve” ?

        • jbogard

          How is it different than a web page that has link called “Approve” that takes me to a screen that has approval information and I hit “Approve”? That request hits a single method in a controller, but I wouldn’t characterize that as RPC.

  • CQRSful in a fully consistent environment, which makes it quite a bit less CQRSful in my view.

    • jbogard

      There’s nothing in CQRS that says you need to be immediately or eventually consistent. There’s nothing that says that there is a maturity model like some have proposed for REST (and eventually, was regretted). There are just different flavors, all with tradeoffs.

      However, you can absolutely do eventual consistency in REST. Just return the “202 Accepted”. That means that the work will be done asynchronously/out-of-band.

      • Absolutely, I think I explained myself better in the comments above. I am trying out your idea of returning status check URLs in a response object, looks very promising. Hopefully I see you tonight in Oslo :)

      • Dave Van den Eynde

        ..or return 200/204 only after it was processed asynchronously (possibly with some timeout falling back to the 202 you mentioned)

  • Eirik Mangseth

    Would you include links to additional resources if the clients were known to be iOS/Android apps only? I.e. you own and provide both client apps and the service endpoints.

  • Ehsan Mirsaeedi

    Thanks for the great explanation. you suggested that we can return some information from our AprroveInvoice command handler. doesn’t this approach against CQRS principles?

  • Brian Elliott

    Slightly off topic, but what would your REST GetInvoice look like when the the business wanted a list of customer specific invoices, assigned to a specific approver, that are over 30 days old, and contains hardware not service SKUs, etc, etc. Do you stick with the GET and hope the business never dreams up enough filters to break the URL max, or is there another approach :)

    • Dave Van den Eynde

      There’s always GET with a specific body. Just because it’s GET doesn’t mean the body has to be empty. You can have the most complicated request in the world.

      If you do put it in the URL, it better be a resolved URI Template that you got from the server.

    • Harry McIntyre

      That’s really a limitation of how browsers/servers implement HTTP, not HTTP itself (http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers).

      The HTTP protocol does not place any a priori limit on the length of a URI. Servers MUST be able to handle the URI of any resource they serve, and SHOULD be able to handle URIs of unbounded length if they provide GET-based forms that could generate such URIs. A server SHOULD return 414 (Request-URI Too Long) status if a URI is longer than the server can handle (see section 10.4.15).

      Perhaps if you ran into this requirement you could extend your API amd documentation and issue a POST with the query in the body, and use X-HTTP-Method-Override:GET (http://www.hanselman.com/blog/HTTPPUTOrDELETENotAllowedUseXHTTPMethodOverrideForYourRESTServiceWithASPNETWebAPI.aspx)

    • Jono

      I do like this question, because there is no good answer for it! I would generally stay away from using the request body for complex queries, although you could quite easily build a query object up this way. However, in the DDD world, you would ask what those invoices represent – some of the filters could become part of the resource endpoint: /customer/1234/invoices/aged, and depending on the business, you could filter client side for the other fields, or if they REALLY wanted the extra filtering, the query string can probably handle the remainder without blowing out the URL limits. Basically, challenging the business on why they want the complex filtering is your best bet to ensure the API remains appropriate. A lot can be done within a BI tool if they just want to report, or get simple lists of these things.

  • niaher

    Awesome post. I’ve been using Mediatr and command-based architecture heavily in the recent past and having task-based UI is the next natural step. The other next natural step is metadata-driven UIs which you briefly hinted at in this post. To be honest I am somewhat surprised that there isn’t much info on the web about metadata-driven UIs (maybe I’m searching for it incorrectly?). It seems like such an obvious thing to do once you have encapsulated all your business logic into IRequestHandler classes.

  • CQRSful made my day.

  • nashvegastech

    Where I am at we are trying to implement REST over CQRS. However, the way some folks here want to implement it seems to have a conflict. Hopefully, you can shed some light for me as I try to grasp the two. I thought that REST Post should return location information as you show above. However, many feel that CQRS (the C part) should never return anything – just fire and forget – that return values are just plain wrong. I am dealing with a number of zealots here who want to do things “the right way” and follow the letter of the law regarding both REST and CQRS. I am not sure if I am confused or they are. Would love your thoughts.

    • jbogard

      Well, at least CQS, the idea is that the command never returns anything. But in CQRS there isn’t a rule that Command never return anything. Nor is there a rule that Command are always async. In fact, Greg has MANY times said commands should be synchronous by default.

      In the real world, you very, very rarely see fire-and-forget commands. Imagine any interaction you’ve had on any website, or even in real life. How many times do you see fire-and-forget commands? There’s almost always at least an acknowledgement of some kind.

  • Joseph Ferris

    Any thoughts on how to apply scalability, using this approach? Specifically, imagine that you wanted to scale your read side and write side based upon usage – i.e. a read-heavy system. The one thing that I keep seeing, in regard to REST with CQRS, is that it is usually very UI-centric, in that the UI is making the calls in to the read or write side. I like the idea of load-balancing the read and write side, preferably with some level of elasticity. For example, let’s say that I want to put a WebAPI facade on my worker roles in an Azure hosting scenario. Is there anything inherently wrong with wanting the ASP.NET MVC controllers, or even the Application Services (should those exist in the implementation) to do the actual communication? On the one hand, it is an additional layer of abstraction – on the other it allows me to keep more of the actual code in C#…

    • jbogard

      First of all, you can implement another decorator as a caching layer around queries. I’ve never done this, so this is strictly a thought exercise. Or you could do that at the layer above MediatR in the controller, if you want the entire request cached?

  • Marcel

    I’m a bit late to this discussion, but after reading the article I have two questions.

    Any specific reason why you use a verb in the approval request? POST /invoices/684/approve vs. POST /invoices/684/approval.
    And in your example, the client needs to know whether to use POST or PUT to approve. Shouldn’t the verb to use be part of the response to GET /invoices/684/approve?

    • jbogard

      It doesn’t matter, the URL should be opaque to the end user anyway.

      • Marcel

        Okay, fair enough. What about the client needing to know whether to POST or PUT?

        • jbogard

          HTML indicates in forms, method=post or method=get, you can do similar in your hypermedia.

  • Correct me if I’m wrong, but I think you’re violating principles of both REST and CQRS here. Doing GET /invoices/123/approve, in order to modify an invoice is by no means RESTful. When I GET, I expect to retrieve only, this should never be a GET. HTTP methods should be meaningful. In case of an invoice approval, I guess , it might be PUT, which is idempotent. And commands are not meant to retrieve data, but only to change it. Of course, no architecture is carved in stone and there should be no Spanish inquisition around it, it’s all about tradeoffs, blah blah blah – but here I have a feeling that above design is an unhealthy mix of REST+CQRS. And + RPC, as someone found below.
    But don’t get me wrong, didn’t mean to hate your post, just disagree with it.

    • jbogard

      I think you’re off on the definition of RESTful. A GET for an approval request at the URL of /invoices/123/approve is RESTful by the definition of REST. If I link to that resource from the invoice resource, it’s RESTful. And I *could* expose PUT, if I wanted the modification of the approval resource to be idempotent.

      But not all invoice approval requests are idempotent. I think you’re mixing REST and the back-end entities that support my operations. From the HTTP perspective, everything we’ve seen so far is absolutely RESTful in that it adheres to the REST architectural constraints.

      • I can see, basing on this reply and other ones as well, that the main explanation for calling GET /invoice/{id}/approve RESTful is that you claim it’s RESTful, which doesn’t convince me… at all. Being idempotent or not is just an example, it depends on your domain, you can POST approval which is not idempotent and it’s fine, but it’s not a GET.

        Here you’ve got an extremely concise explanation on why a GET can’t modify anything on the server-side: http://softwareengineering.stackexchange.com/a/188861/87707, one of the reasons is default caching, the other one is that you expect to get the same data no matter how many times you make the call. Moreover, see this: https://www.w3.org/2001/tag/doc/whenToUseGet.html#checklist. You are clearly violating RESTful principles here, but it’s not my mission to convince you.

        • jbogard

          The reasons it’s RESTful is that it adheres to the REST constraints. That’s all it takes for something to be RESTful.

          I don’t know why you’re talking about GET modifying anything, I never suggested that GET modifies anything? Or that a GET for an invoice approval resource actually mutates anything? In a Regular Web App ™ you GET the invoice (or list of invoices) and there’s a link to the approval resource. You can GET that which will return a form, that you then POST:

          GET /invoice/1234
          GET /invoice/1234/approval
          POST /invoice/1234/approval

          The 2nd GET is a means of retrieving the form template/hypermedia control for itself, but it sounds like you’re indicating that I suggested to use GET for creating an approval – but I did not. POST for a new approval resource request, or PUT if you want that to represent not an “approval request” but “literal approval on this resource”. Which I almost never do, it’s nearly always a request by the client to do something.

          • GET /invoice/1234
            this GET is absolutely fine, but…

            GET /invoices/684/approve
            this is not. “approve” is a verb (operation), not a noun (resource). By convention, you don’t use verbs in REST, but that’s just a convention, though useful. The real issue is that you are modifying the invoice:684 by calling this request, don’t you see it?

            PS “The reasons it’s RESTful is that it adheres to the REST constraints. That’s all it takes for something to be RESTful.” – I find this a hand-waving reasoning. Having removed these sentences, you still have the information.

          • jbogard

            Hold on, in REST, a resource is anything with a URI. That’s the definition of a resource, period. I could have named the approval resource URL “/fluffybunnies/NOT_THE_REAL_ID/petvigoruously”. In fact I could have obfuscated all my URLs as random GUIDs :) . URL design is completely orthogonal to “REST”. URL design is akin to button labels. That my approval resource is “under” the invoice resource URL is immaterial – it’s a different resource. The operation itself is my resource, as a command.
            REST doesn’t mention verbs or nouns, either. That also has nothing to do with RESTful. RESTful = “adheres to REST constraints”. That’s not my definition – it’s the definition of the person that invented the term REST.
            Unless you want to redefine REST. Or conflate “back-end entities” with “resources” and “representations”, which is a common mistake with people I’ve seen label CRUD APIs as “RESTful”.

            In fact, those web apps you built without any javascript SPA junk, guess what, those were RESTful, if you choose to adopt the definition of REST by the person that invented the term.

  • Haya Runa

    Why do it easy if we can do it hard and complex Right ?