Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why the domain model should not be used as resources in REST API?

I came across a statement that the domain model designed in accordance with DDD should not be used as resources in a REST API (source).

It is clear that a REST API is a contract of the application while the domain model is part of the implementation and therefore it is the best to keep these two things separate, so that a change in the domain model does not automatically imply a change in the REST API.

However, I think in case of small projects (where the REST API has just one consumer - the javascript frontend, developed by one team) the benefits of having separate models does not justify the cost of separating the models (different classes - domain model and resource representations and mapping code between the models). Obviously the domain layer cannot have any references to REST specific infrastructure code (to keep separation of concerns).

Should the domain and the REST models be separated?

like image 740
Adam Siemion Avatar asked Nov 28 '15 11:11

Adam Siemion


3 Answers

When using DDD, the REST API should always be separated from the domain model.

The main reason for this is simplification - you don't want to leak the complexity of the domain model through the API to the clients. Otherwise, clients need to know about the nuances and intricacies of your domain, which most probably makes the API hard to use.

And the main driver for using DDD is a complex problem domain, so this is always a problem.

However, I think in case of small projects (…) the benefits of having separate models does not justify the cost of separating the models (…).

I agree that there are projects where a separated domain model and REST API is over-engineering. However, these cases aren't candidates for DDD, because you will not benefit from DDD enough to justify its cost.

like image 172
theDmi Avatar answered Oct 20 '22 14:10

theDmi


Why the domain model should not be used as resources in REST API?

Because the web is a totally different world than your core domain layer. The methods in your entities are especially hard to translate since HTTP only has a handful of verbs. If you want to expose your application via REST, you have to shoehorn your domain processes into HTTP and that usually means making compromises and designing resources that are different from your domain entities.

Of course you should find terms from the Ubiquitous Language in the messages exchanged between the HTTP client and server and in the Domain Application Protocol if you're doing HATEOAS, but the web will necessarily distort your domain representations.

The point of REST is not to re-create a high fidelity model of your domain and its processes, but to deliver them in an HTTP compliant way while losing as little as possible in translation. Yet it remains a translation.

like image 32
guillaume31 Avatar answered Oct 20 '22 15:10

guillaume31


I think the main benefit of REST APIs is providing a service for (typically server side and not SPA) 3rd party REST clients. If you use HATEOAS and other self-descriptive message solutions like RDF, then the REST clients will break a lot harder due to changes in the REST API. For small projects - "where the REST API has just one consumer - the javascript frontend, developed by one team" - I don't think it's worth the effort to have a proper REST API. Most people use the simplified version of it, which I call CRUD API, those might be good for these projects.

There can be an 1 to 1 mapping between the CRUD resources and the domain objects of an anaemic domain model. If we are talking about real objects (instead of data structures) with more than just CRUD methods, then you have to translate between resource.verb and object.method, for example:

POST /dogs/{id}/barking
 -> domain.dog.bark()

If we are talking about more complex things involving multiple domain objects and unit of work (transactions), then you need to add another layer for the application services, otherwise you would move the whole complex operation including the transaction handling to the client. In those cases you translate between resource.verb and applicationService.operation for example:

POST /dogs/{id1,id2,..}/barking
 -> dogService.multiDogBark(...)
 -> UnitOfWork{domain.dogs[ids[i]].bark()}

I think most of the developers confuse this CRUD services + anaemic domain model approach with the REST services + domain model approach, that's why this question is asked and that's why there are many "REST" frameworks which add 1:1 domain object - CRUD resource mapping or maybe even ORM entity - CRUD resource mapping. I find this trend very destructive and I think the main cause that developers learn certain technologies only superficially from short articles or Q&A sites instead of reading books and dissertations where they can get deep knowledge in the actual topic. I think this is an Y+ generation problem, that we are losing the ability to read long texts because of the usage of the digital technology. We are conditioned to instant rewards instead of the delayed reward a long text gives...

like image 4
inf3rno Avatar answered Oct 20 '22 14:10

inf3rno