I use SpringBoot and I have some Reactive APIs (Controller call a service which call a repository based on MongoReactiveRepositories)
As I don't want the user to directly see my models objects, I would like to have DTOs.
One DTO can be based on the information of several models.
Ex: Given two Model Items
ItemA:
infoA:String
ItemB:
infoB:String
I want to create a single DTO item
ObjectDTO:
infoA: String
infoB: List<ItemB>
What is the proper way to reactively map data between my objects model and a DTO?
Just use Mono.zip(https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#zip-reactor.core.publisher.Mono-reactor.core.publisher.Mono-java.util.function.BiFunction-) to combine 2 results into one.
return Mono.zip(repo1.getItemA(), repo2.getItemB(),
(itemA, itemB) -> new ObjectDTO(itemA.getInfoA(), itemB.getInfoB())
);
The methods returning itemA and itemB should ofcourse return a Mono.
Related
In Spring MVC we have 3 main categories of objects: Controllers, Services and Repositories.
I'm not able to "categorize" the objects returned by these three categories.
For example, the repositories return Entitys, but how could I name the objects returned by services and controllers?
In a real project I'm developing I have a repository returns an extraction from a table, so I get Entities objects. Into the service, where the logic is, I need only to return some fields, so I need to map the entities to another object-model. Later into the controller maybe I will need some layer specific presentation, for example between "standard-computer" and mobile, so I need another type of object to map the result of the service.
Each layer has its postfix in the name of the class to keep the codebase clean and readable. In most of the projects I have worked on, the naming convention is:
Controller layer
The POJO exposed outside of the application, for example, thought a REST API is DTO (Data Transfer Object), so it is usually under the dto package, and the name is like UserDto
Service layer
The POJO that handles the application's business logic is called domain object, so it is usually under the domain package, and the name is like User without any postfix in the name.
Repository layer
The POJO that holds the data in the persistence layer is called entity, so it is usually under the jpa package, and the name is like UserJpa
I am using MVC pattern abstracted with domain layer. I could convert a domain object into its equivalent DTO and sending it across top layer (ie controller & ultimately to views). Now how to do the reverse? How & where will I construct the actual DTO object and pass it to the controller?
I have found the best way to do this is have a DTO service layer. This will be a collection of functions that the controller (or anything else) can call to retrieve and convert DTO's.
I would also recommend doing the domain object to DTO mapping (and the reverse) in this layer too, it keeps all the DTO related logic in one layer.
Below is an example of a DTO service layer function:
public CustomerDto GetCustomer(Guid customerId) {
var roService = new RoService<Customer>(new Repository<Customer>(_dbContextFactory));
return _mapper.ToCustomerDto(roService.Get(customerId));
}
This will retrieve a Customer entity by its Id. The entity is passed to a mapper object which will convert it to a CustomerDto for it to be returned.
N.B. I used AutoMapper to convert my domain objects to DTO's.
I'm currently experimenting with OData endpoints in ASP.NET MVC 4 Web API. I like the concept and try to come up with efficient ways to use it in our project.
One question I have is the following: we have a service that is able to return an IQueryable and takes the name of an entity as Input:
public IQueryable GetAll(string entityName);
In standard Web API (as opposed to OData Controllers) I can create a generic controller, that can be called in the form /api/entities/{entityName} and returns the IQueryable.
In case of an OData Controller, I carry out the following entity-specific steps:
Register the entities in the model.
Create a separate Controller for each entity that derives from EntitySetController<>.
I want to use the generic service and avoid as much entity-specific implementations as possible. The first step can easily be automated if the service can return a list of the entities and the corresponding types.
That leaves step 2, because up to now I need to create a specific controller for each entity. I also want to avoid that and create a generic controller that uses the generic service.
Can anyone recommend a solution, maybe by influencing OData routing?
You can create a custom routing convention that selects the same controller no matter what the entity set is. Example,
public class CustomControllerRoutingConvention : IODataRoutingConvention
{
public string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, ILookup<string, HttpActionDescriptor> actionMap)
{
return null;
}
public string SelectController(ODataPath odataPath, HttpRequestMessage request)
{
return "SomeFixedContrllerNameWithoutTheControllerSuffix";
}
}
You can register that routing convention using the following code,
IList<IODataRoutingConvention> routingConventions = ODataRoutingConventions.CreateDefault();
routingConventions.Insert(0, new CustomControllerRoutingConvention());
config.Routes.MapODataRoute("OData", "odata", builder.GetEdmModel(), new DefaultODataPathHandler(), routingConventions);
I came up against the same problem, and ended up writing a custom IHttpControllerSelector instead of an IODataRoutingConvention. IODataRoutingConvention looks like a good option if your generic controller doesn't require generics :) . But since IODataRoutingConvention.SelectController() only returns a string, I don't see how it will work for instantiating a controller with generic type parameters.
I decided this problem needs a good, general-purpose, open-source solution - so I created one: https://github.com/EntityRepository/ODataServer . It's prerelease now, but I'm currently doing a lot of work on it. I think there's more to it than just choosing the right controller, there are general patterns to define for shared controllers, and by default Web API OData expects strongly typed and strongly named navigation properties which makes it challenging to create a re-usable implementation.
What do you think about exposing domain entities through services? I tried it in an application, but I came to the conclusion that exposing domain model to the client is not such a good idea.
Advantages:
Really easy to transport data from-to client
List item
(De)Serialization is really easy: just put jackson in the classpath and it will handle it. No extra logic is needed.
No need to duplicate entities POJOs. At least in early stages, the API resources will be pretty much the same as the domain model.
Disadvantages:
The API's get very tightly coupled to the model and you can't change the model without affecting the API
Partial responses. There are cases where you don't want to return all the fields of the entities, just some of them. How do you accomplish it?
So, let's take the following REST example. The following API declares that GET on the user resource returns the following information.
GET
/users/12
{
"firstName":"John",
"lastName":"Poe"
"address":"my street"
}
Usually, I would create a User entity, a user service to return the user and a REST controller to serve the request like this:
#RequestMapping("/users/{id}")
public #ResponseBody User getUser(#PathVariable Long id) {
return userService.findById(id);
}
Should I avoid returning the User entity?
If yes, should I create another class and handle myself the mapping between this class and the entity?
Is there a pattern for this?
How to accomplish partial expansion? (i.e. return only the firstName and lastName for the user)
P.S: using #JSONFilter and ObjectMapper to accomplish partial responses seems too heavyweight to me because you loose the beauty of spring data
I'm using spring mvc.
I have created the controller, view, pojo, dao.
Now I have the need to create an object composted from multiple objects pojo, is the case of creating a DTO?
If you're looking to build a composite kind of Object for view purposes only, then there is a good argument for a DTO. If the composite is just an aggregation of the POJOs you can use org.springframework.ui.Model and just add attributes inside your Controller. If there is logic and business rules that need to be applied, it is probably best to do this in a Service layer that sits between your Controller and your DAO.
If you mean that you need to access properties of few POJOs on the client side and you want to reduce amount of calls from
client to server then yes. It is better to create a DTO object where place only necessary properties from POJOs that you will
use on client side. And return this DTO as a result of a single call from client to server.