Rickard Oberg is popular among Java developers. He has given seminars at all main Java conferences world wide. He worked as an architect at JBoss and other popular OpenSource Java frameworks, and wrote a book on RMI. In recent years, he has become famous as an Aspect Oriented Programming (AOP) crusader. He has worked with bleeding edge AOP in a portal product that has become a great commercial success, and is currently working on Qi4j at Jayway. Rickard is a DZone MVB and is not an employee of DZone and has posted 16 posts at DZone. You can read more from them at their website. View Full User Profile

REST API: for Infrastructure, Domain or Application Layer?

10.18.2010
| 9149 views |
  • submit to reddit

It seems that lots of projects/products/services want to expose a REST API these days. But I have found very few that actually follow the REST constraints, and in a lot of the cases it doesn't even make sense for them to follow REST constraints in the first place.

One of the main constraints that is commonly violated is the hypertext constraint. Basically, all state changes have to be done by following links, starting from a bookmarked URL. But almost noone does that. However, should they? This article will outline various layers that REST API's can be implemented in, and when it makes sense, and when not.

To begin with, in a typical enterprise app there are three options for layers that you might want to expose using a REST API. These are the infrastructure layer, the domain layer, and the application layer.

Infrastructure layer

If we start with the infrastructure layer, we are typically talking about a database vendor that wants to allow developers to access it using "REST". The API would allow you to create/remove databases, and then insert/update/delete data. Typically it's pretty normal stuff, and the API doesn't change all that much between versions. Accessing this over HTTP maybe makes sense, but is it RESTful?

I'll give you an example. I installed CouchDB, and given the hypermedia constraint I should then be able to go to "http://localhost:5984/", and it will tell me what I can do next (like create a database). But when I do a GET on that URL I get this:

{"couchdb":"Welcome","version":"1.0.1"}

So now what? The hypermedia doesn't tell me what I can do, so therefore as a REST client I will assume there's nothing I can do. This very simple test shows that the HTTP API for CouchDB isn't really RESTful at all. The question is: should it be?

That is obviously up to the developers to decide. But if I were the architect I would maybe say, no, it shouldn't be RESTful. Why? Because I want to allow URL templates to be used, so that the client, given the server URL and a document id, is allowed to construct a URL on its own and GET the document. If this was truly RESTful the client would have to do a query in a form first, with the id, in order to get the URL of the document to be retrieved. That might be inefficient for a database, so I might opt not to do this. Which is, in effect, what they already have done. The only problem is that they call it RESTful, when it isn't, so it gives me as a developer the wrong impression of what I can expect from it.

This line of reasoning could be done for pretty much most infrastructure layer API's. They're not RESTful, though many say they are, and most likely they shouldn't try to be! IT'S OK! Just say "Accessible over HTTP, see docs for URL templates and whatnot", and be done with it.

Domain layer

The next potential layer to be exposed over REST is the domain layer. This typically means that you take your domain entities and expose their data straight on the web, through CRUD operations. Very straightforward. There are tons of articles and blogs that show how to do this. But is it RESTful? Or is it even a good idea in the first place?

The first test, again, would be to see if the app follows the hypermedia constraint. In this option it is technically possible to allow queries that will list the various URL's to entities in your domain, which you then can update/delete. So on the surface it might seem like you are following the hypermedia constraint.

The problem usually comes with the fact that you are exposing domain state rather than application state. Let me explain through a simple example. Let's say you are building an issue tracker. You can access individual issues through links like:

/issue/123

which on GET gives you documents such as:

{"status":"OPEN","description":"Some issue"}

Awesome. Now a client can change the status to "CLOSED" and PUT that. Tada! Case closed.

Or is it? What if a client then decides to reopen it, by simply posting a new status of "OPEN" to it. Ok, that worked. But should it? Maybe your domain model really would have wanted it to only go to "REOPENED" from the "CLOSED" state. But how do you express that? How is the client to know that this is the only valid transition? And what happens when we have many versions of clients, each of which has a slightly different set of rules for what you are allowed to do when? Basically, chaos is ensured.

And this is the problem with exposing your domain model using a REST API. The client has to own the application logic, and there's no way the server can be sure that it has the "right" logic. And the client, even if it *wants* to play nice (if code ever wants anything is debatable), will have a hard time knowing whether it is playing by the rules or not. It might even get a bit neurotic, trying to do the right thing, whatever that means.

In summary, exposing your domain model does not help the client know what the valid state transitions are, and makes it very hard to do other things like role-based security authorization (maybe only an admin is allowed to REOPEN a CLOSED case?). I would therefore recommend that noone exposes their domain models using a REST API.

Application layer

Finally we come to the application layer. The application layer is designed to implement usecases of the domain model, and has all the context and logic needed to ensure that only valid state transitions are made. In short, it seems like it is especially appropriate to being exposed through a REST API, as it can at all points tell the client what it can do (either based on state or authorization rules or any other type of rules it might have).

If we go back to the issue tracker, what would this mean in practice? It could mean that when you do a GET on /issue/123 you get something like this back:

{"data":{"status":"OPEN","description":"Some issue"},"links":[{"close":"/issue/123/close.json"}]}

This now instead of referring to viewing the domain state of an issue refers to the usecase of viewing an issue with the intent of working on it. There might be other URL's and other queries that only return the data, or maybe a table of the data, or somesuch. But this one, specifically,  refers to the usecase of working with the issue. So, as a REST client I can now inspect the data, and then look at what links are available. If the client has a UI it can enable a button that says "Close issue" based on the available link, since it detected a link relation "close" that it understands. The client can then do GET on that link, find out whether the server expects any form to be filled in, and then submit it using POST, thereby letting the server application layer logic transition the issue to the "CLOSED" state.

We are no longer relying on the client to contain the logic of knowing when to allow what, and the client also does not have to know how to construct the URL. As long as it can parse the hypertext (and we might use a custom JSON mediatype to indicate what "data" and "links" mean) and do something with it, we're fine. If we in the future change the domain model to also allow the "resolve" link relation for "OPEN" issues, old clients can ignore it, and new clients can enable new actions in the UI that uses it.

In summary, the application layer is a very good candidate to be exposed through a REST API. It encapsulates the application rules for when the various state transitions are allowed, and can make use of user authorization to further enable/disable actions. This takes away a lot of responsibilities from the client, which now also can be "dynamic" in the sense that it can easily react to what state changes are available when by simply checking link availability in the hypermedia returned from the server.

The main issue with exposing the application layer through a REST API is that there are pretty much no available frameworks that help you do all this in an easy way. But this is not REST's "fault", obviously, but rather that the "REST" community hasn't yet matured to understand what it should and what it should not do.

In the Streamflow project we rolled our own simple framework for doing the above, and I'm very happy with that, but unfortunately most other frameworks seems to be in the "expose your domain model" camp, which means that a lot of this link management is non-trivial to do. This is a fixable situation though.

I hope that this post has somewhat clarified what the issues are with exposing infrastructure and domain models through REST API's, and why it's not really a good idea in the first place, and why exposing the application layer really is the logical and simpler option.

 

From http://www.jroller.com/rickard/entry/rest_api_for_infrastructure_domain

Published at DZone with permission of Rickard Oberg, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Jochen Bedersdorfer replied on Mon, 2010/10/18 - 9:08pm

In my  world, if you have a domain model, you have defined all possible states and state changes within that model. Otherwise it is just a data model, not a domain model.

But fans of humongous stateless session beans would disagree, I guess.

 In any case, exposing an object-oriented model (and business logic) as resources in a RESTful world suffers from a similar impedance mismatch as the one encountered when mapping OO data models to an RDBMS.

 In a RESTful world, you are talking about exchanging representations of resources using just a handful of methods.

This bare-bones interaction model will require rethinking your domain model in light of a RESTful architecture. (And this is the no. 1 thing creators of RESTful APIs are not taking into consideration. REST is an architectural STYLE, not an actual architecture.)

HATEOAS is one part of it (often there is a mapping from internal object-ids to URLs to link resources), but you might be forced to add additional concepts, expressed as resources to your API.

This often happens with actions or activities that would be expressed as a VERB or a method in a regular OO-model. The more RESTful way here might be to translate those to NOUNS e.g. actual resources.

One example would be sending an e-mail through a RESTful service and tracking the status of said e-mail. Your domain-model might have a send(msg); or msg.send(); method somewhere with an asynch notification service your client is registered with to track progress.

In a RESTful design, you might be better off creating a new resource, let's call it /delivery for example, to express this: POST the e-mail to resource /delivery which returns a link to the newly/temporarily created delivery/4711 resource.

 Now the client can monitor that resource to get notified of the progress and can also remove it if it's not needed anymore. The client can also recover by requesting all current delivery resources, should it restart.

In your OO-design phase, you never accounted for this to be an object. In a RESTful world, it absolutely makes sense.

 

Christian Reichel replied on Tue, 2010/10/19 - 7:26am

Excelent post Rickard.

I just would like to say that exposing the application layer, in the way that you explain is a much more service oriented way to design the application.

Regards.

Benjamin Young replied on Fri, 2010/10/22 - 1:22pm

Rickard, you might enjoy checking out Leonard Richardson's "Maturity Model" for RESTful API's. Leonard is the main author (with Sam Ruby) of the RESTful Web Services book from O'Reilly.

In the Maturity Model, CouchDB's "HTTP CRUD" API would be at Level 2. At this point, there's little use for a Level 3 API (as you pointed out) for CouchDB as what it does is farily straight forward. However, if/when JSON gets a Hypermedia format (and the mandatory registered media type to go with it), a full Level 3 API might be worth considering.

One great thing about CouchDB "stopping" at Level 2 is that it gives the app developers the opportunity (and tools) to augment that API with their own Level 3 API's using a combination of the _rewrite, _update, and _show/_list handlers. That API could even use XML+XLink (rather than JSON) or (X)HTML to provide the necessary Hypermedia data that JSON currently lacks. That's all doable now with CouchDB 1.0.1, which makes CouchDB a great platform for creating RESTful API's (IMO).

There is work begin done on a Hypermedia JSON format by several different developers. The most notable one is probably the one connected with JSON Schema (both written by Kris Zyp). There's a schema for it at the JSON Schema site. JSON Schema's written in such a way that Schemas can be easily extended, so other "child" document types could extend this Hyper JSON format to benefit from the common (and eventually registered) media type + their own data. All of which would be quite fabulous (agian, IMO). :)

Thanks for the article, Rickard, and for the review of CouchDB's API and RESTful API's in general. Keep up the great work.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.