Do RESTful APIs tend to encourage anemic domain models?

by Kazark   Last Updated November 14, 2017 17:05 PM

I'm working on a project in which we are trying to apply both domain-driven design and REST to a service-oriented architecture. We aren't worrying about 100% REST compliance; it would probably be better to say we are trying to build resource-oriented HTTP APIs (~Level 2 of Richardson's REST maturity model). Nevertheless, we are trying to stay away from RPC-style use of HTTP requests, i.e. we attempt to implement our HTTP verbs according to RFC2616 rather than using POST to do IsPostalAddressValid(...), for example.

However, an emphasis on this seems to be at the expense of our attempt to apply domain-driven design. With only GET, POST, PUT, DELETE and a few other rarely used methods, we tend to build CRUDdy services, and CRUDdy services tend to have anemic domain models.

POST: Receive the data, validate it, dump it to the data. GET: Retrieve the data, return it. No real business logic there. We also use messages (events) between the services, and it seems to me that most of the business logic ends up being build around that.

Are REST and DDD at tension at some level? (Or am I misunderstanding something here? Are we maybe doing something else wrong?) Is it possible to build a strong domain model in a service-oriented architecture while avoiding RPC-style HTTP calls?



Answers 7


POST was deliberately designed to be "intentionally vague;" the result of a POST is implementation-specific. What prevents you from doing what Twitter and other API designers do, and define each POST method in the non-CRUD portion of your API according to your own specific requirements? POST is the catchall verb. Use it when none of the other verbs are a good fit for the operation you want to perform.

To put it another way, your question could be equally posed as "Do 'smart' objects encourage RPC-style design?" Even Martin Fowler (who coined the term "Anemic Domain Model") concedes that bare DTO's do have some benefits:

Putting behavior into the domain objects should not contradict the solid approach of using layering to separate domain logic from such things as persistence and presentation responsibilities. The logic that should be in a domain object is domain logic - validations, calculations, business rules - whatever you like to call it.

Regarding the Richardson Maturity Model, you can get to level 3 without ever concerning yourself about "Anemic Domain Models." Remember, you're never going to transfer behavior to the browser (unless you plan on injecting some Javascript through your models).

REST is mostly about machine independence; implement the REST model to the degree that you want your endpoints to represent resources, and for consumers of your API to be able to easily access and maintain those resources in a standard way. If that seems anemic, then so be it.

See Also
I Need More Verbs

Robert Harvey
Robert Harvey
January 14, 2014 21:17 PM

Martin Fowler's first law of distributed systems: "Don't distribute your objects!" Remote interfaces should be coarse-grained and internal interfaces fine-graned. Often rich domain model only applies within a bounded context.

REST API separates two different contexts both having their own internal models. The contexts communicate through coarse-grained interface(REST API) using "anemic" objects(DTO).

In your case it sounds like you are trying to spread a context over a boundary that is REST API. This can lead to fine-grained remote interface or anemic model. Depending on your project it may or may not be a problem.

simoraman
simoraman
January 15, 2014 06:18 AM

IMHO I don't think they tend to encourage anemic domain models (ADMs), but they do require you to take some time and think things through.

First of all I think the main characteristic of ADMs is that they have little to no behaviour in them. That's not to say that the system has no behaviour, just that it's usually in some sort of Service class (see http://vimeo.com/43598193).

And of course if the behaviour doesn't exist in the ADM, then what does? The answer of course is the data. And so how does this map to REST API? Well presumably the data maps to the content of the resource, and the behaviour maps to the HTTP verbs.

So you have everything you need to build a rich domain model, you just have to be able to see how the HTTP verbs map to the domain operations on the data, and then put those operations in the same classes that encapsulate your data.

I think where people tend to run into problems is that they have a difficult time seeing how the HTTP verbs map to their domain behaviour when the behaviour is beyond simple CRUD, i.e., when there are side-effects in other parts of the domain beyond the resource being modified by the HTTP request. One way to solve that problem is with domain events (http://www.udidahan.com/2009/06/14/domain-events-salvation/).

RibaldEddie
RibaldEddie
January 15, 2014 06:47 AM

Is your problem that you're trying to cram your model into the basic set of verbs, using POST as much as possible?

Its not necessary - I know that to most people REST means POST, GET, PUT and DELETE, but the http rfc says:

The set of common methods for HTTP/1.1 is defined below. Although this set can be expanded, additional methods cannot be assumed to share the same semantics for separately extended clients and servers.

And systems such as SMTP use the same style of verb-based methods but with a totally different set.

So, there's no reason why you have to use these, you can use whatever set of verbs you like (though, really you will find that you can do everything you need in the basic 4 with a bit of thought). The thing that makes REST distinctive from the other mechanisms is its stateless and consistent manner of implementing these verbs. You should not try to implement message passing system between the tiers as you're basically not doing REST then, you're doing a message-passing, RPC or message-queue mechanism instead which will undoubtedly lose you the benefits of REST (ie the simplicity of it that makes it work really well over a http connection).

If you want a full-features, complex messaging protocol, then build that (if you can do so over the web, there's a reason why REST is so popular), but otherwise try to stick to the architectural design of REST.

gbjbaanb
gbjbaanb
January 15, 2014 13:21 PM

Several reasonably successful implementations I have seen/built answer the question in how they mix the verb+noun metaphor using coarse-grained 'business friendly' methods that act on the entities.

So instead of the (doomed) getName() method/service, expose getPerson(), passing in things like identifier-type/ID, returning the entire Person entity.

Since behaviors of the Person entity in such a context cannot be adequately conveyed (nor perhaps should they be in a data-centric context as this), it is perfectly reasonable to define a data (versus Object) model for the request/response pairs of the service/s.

The services and defined verbs themselves will add some domain-allowed behaviors, controls and even state-transition rules for the entities. For example, there would be domain-specific logic as to what happens in the transferPerson() service call but the interface itself would only define the inputs/output entities/data without defining THEIR internal behaviors.

I would disagree with authors that would say, for example, a transfer verb implementation belongs in the Person class or associated with a Person-centric service. Indeed, the method of transfer for a Person and options thereof (in this simple example) would be better defined by a Carrier, wherein the Person may have no knowledge of even what transfer methods are available or how transfer even takes place (who knows how jet engines work anyway).

Does this make the Person entity anemic? I don't think so.

There can/should be logic about Person-specific things that are internal to Person like their state of health, which should not be defined by an external class.

However, depending on the use-cases, it is entirely acceptable that an entity class have no important/relevant behaviors in certain systems, such as a seat-assignment service in a transport system. Such a system may well implement REST-based services that deal with Person instances and associated identifiers but never define/implement their internal behaviors.

Darrell Teague
Darrell Teague
March 20, 2014 22:36 PM

REST API is just one type of presentation layer. It has nothing to do with the domain model.

The question you posted comes from your confusion that you somehow need to adapt one to another. You don't.

You map your domain model to your REST API the same way you map your domain model to an RDBMS via an ORM — there has to be this mapping layer.

Domain ← ORM → RDBMS
Domain ← REST Mapping → REST API

Elnur Abdurrakhimov
Elnur Abdurrakhimov
May 17, 2014 13:09 PM

This article is quite related to the subject and I believe answers your question.

A core concept that I think answers your question very well, is summarized in the following paragraph from the mentioned article:

"It is very important to distinguish between resources in REST API and domain entities in a domain driven design. Domain driven design applies to the implementation side of things (including API implementation) while resources in REST API drive the API design and contract. API resource selection should not depend on the underlying domain implementation details."

Majix
Majix
November 14, 2017 16:09 PM

Related Questions



Ubiquitous language and resource based REST API?

Updated June 15, 2016 08:02 AM


What is a domain?

Updated October 23, 2017 18:05 PM

Domain model design

Updated July 23, 2016 08:02 AM