Rest API - Dtos or Not

What is the difference between DTOs and API Resources

In a REST or Web API, the resource is the object that the methods are operating upon. For example, get a list of Contact, get a specific Contact by ID, update a Contact, delete a Contact - the Contact is the resource.

A DTO (Data Transfer Object) is one way of implementing such a resource. It is often used when the API is modifying data in a relational database. People have discovered pitfalls with returning a Contact database entity directly to a client over a Web API. So they map the Contact Entity to a Contact DTO.

So a Web API Resource might be a DTO but it doesn't have to be. That would depend on your situation. Imagine you have a Web API to get/set the time of day on a device. You wouldn't need to create a DTO for this, you could just use a string representing the date. In that case, the Resource of the API would be a string.

Microservices Restful API - DTOs or not?

The Pros of Just exposing Domain Objects

  1. The less code you write, the less bugs you produce.

    • despite of having extensive (arguable) test cases in our code base, I have came across bugs due to missed/wrong copying of fields from domain to DTO or viceversa.
  2. Maintainability - Less boiler plate code.

    • If I have to add a new attribute, I don't have to add in Domain, DTO, Mapper and the testcases, of course. Don't tell me that this can be achieved using a reflection beanCopy utils, it defeats the whole purpose.
    • Lombok, Groovy, Kotlin I know, but it will save me only getter setter headache.
  3. DRY
  4. Performance

    • I know this falls under the category of "premature performance optimization is the root of all evil". But still this will save some CPU cycles for not having to create (and later garbage collect) one more Object (at the very least) per request

Cons

  1. DTOs will give you more flexibility in the long run

    • If only I ever need that flexibility. At least, whatever I came across so far are CRUD operations over http which I can manage using couple of @JsonIgnores. Or if there is one or two fields that needs a transformation which cannot be done using Jackson Annotation, As I said earlier, I can write custom logic to handle just that.
  2. Domain Objects getting bloated with Annotations.

    • This is a valid concern. If I use JPA or MyBatis as my persistent framework, domain object might have those annotations, then there will be Jackson annotations too. In my case, this is not much applicable though, I am using Spring boot and I can get away by using application-wide properties like mybatis.configuration.map-underscore-to-camel-case: true , spring.jackson.property-naming-strategy: SNAKE_CASE

Short story, at least in my case, cons doesn't outweigh the pros, so it doesn't make any sense to repeat myself by having a new POJO as DTO. Less code, less chances of bugs. So, going ahead with exposing the Domain object and not having a separate "view" object.

Disclaimer: This may or may not be applicable in your use case. This observation is per my usecase (basically a CRUD api having 15ish endpoints)

4 DTOs by default for Spring REST API?

Software design is not a set of rules to be followed without thinking. Rather, software design is a means to pursue your goals - and different goals may require different means.

So when somebody tells you to create separate DTOs, you should ask (or actually, they should have told you without prompting) why they recommend this, so you can assess whether their goals and circumstances match yours.

Since I am not the person who suggested you create 4 different DTOs, I can only speculate about the goals and circumstances that may have prompted such a recommendation, but I can say with certainty that these goals and circumstances are not universal, and many applications get by just fine with far less DTOs.

Reasons for separate request/response DTOs:

  • if fields are read-only, they make sense in the response, but not in a request. Sure, you could simply ignore these fields in the request, but this may surprise the users of your API, and whoever implements the API might accidentally use the field that was intended to be read only. By removing these fields from the request DTO, you remove this ambiguity.

Reasons for same request/response DTOs:

  • simplicity
  • ease of use (the client can send the DTO he received back to the server)

Reasons for different rest/service DTOs:

  • you need to use the same service from different REST controllers, for instance because you have changed the data contract, but need to keep the previous version operational until all API clients have upgraded
  • harder to accidentally change the data contract (which would break your API clients)

Reasons for same rest/service DTOs:

  • simplicity

As you can see, it depends. But many apps use the same DTO for requests and responses, controllers and services. You should only make additional work for yourself if you see a clear benefit of doing so.

Are DTO's necessary when sending JSON from a RESTful web service?

Assuming you talk about serializing entities to json instead of using DTOs which is not very clear, yes DTOs would be the proper choice from an architectural point of view. Underneath controllers there most commonly is the service layer which functions on some domain, let's say persistence entities or entities coming from a queuing system.

It is sane to isolate your REST API from your domain and map lower level domain entities to DTOs at service level, most commonly using a POJO mapper.

This would have some performance impact which you can optimize but has the benefit of structural isolation between layers.

The second benefit is that you can aggregate information from lower layers and manipulate your REST interface as serves you best,

If again we talk about entities it's wrong to add REST api attributes in persistence layer.

All this from a conceptual point of view.
Another thing that should prevent you from serving entities of JPA2 is that the objects returned from queries are enhanced objects so using a mapper will again give you more control.

Choosing the mapper configuration is a bit tricky though since if you expose crud operations as in the persistence/domain level mapping becomes redundant.
Exposing entities will only cause scaling problems

Reusing DTO for various request/response types vs explicitness of what is required / what should be returned

Separate, simple DTOs will make your life infinitely easier. It will require more code, but it will be boring, simple code, that is easily tested, and allows your interfaces to change and evolve independently.

Make a DTO for each request endpoint and a separate DTO for each response. Otherwise, you will eventually be sad.

If you find elements that are common to multiple endpoints, extract them into their own object, and include them in both.

And yes, using inheritance here would be wrong. Stick to compositional patterns and you will be fine.



Related Topics



Leave a reply



Submit