Spring Response\Request body templates - spring-boot

Let me explain a problem. Suppose I have an entity class User:
public class User {
private UUID id;
private String login;
private String password;
private String firstName;
private String lastName;
private String email;
private int age;
// ... more fields and default getters and setters
}
In addition, I have two DTO classes:
public class UserLogin {
private UUID id;
private String login;
// ... getters and setters
}
public class UserLoginEmail {
private UUID id;
private String login;
private String email;
// ... getters and setters
}
Let's take a look to class UserController that has UserLoginEmail as request body and UserLogin as response body:
#RestController("/users")
public class UserController {
#PutMapping
public UserLogin someRequest(UserLoginEmail user) {
// ...
}
}
What is the best way to create some kind of projections in Spring Boot? Can I create an interface with required fields and just put them in the Java method as parameters (or some other way)? I want to build DTO classes with the least effort and agile in my code.

You could use JSON Views with Jackson with which you could define different views on a per endpoint basis (check https://www.baeldung.com/jackson-json-view-annotation for more details).
But in your case, I wouldn't do that. One of your DTOs is a request and the other is a response so you shouldn't mix them together in a single DTO. Even more than that, I don't really like JSON Views because they are simply hard to follow and the code becomes harder to read. Abstractions and code reusability are usually good but it makes the code much harder to read and for the case of DTOs I much more prefer to be explicit and have multiple DTOs even that they are similar. With this approach, you will make it possible to easily change one of the DTOs without affecting anything else, which is not the case when you reuse them in any way.
Having said that, keep both DTOs, but I would rename them: UserLoginRequest and UserLoginResponse.

Related

OpenApi add example for request body

Am working with Spring boot and I am using springdoc-openapi-ui to generate spec files using swagger editor
The issue Is, Am trying to avoid creating model classes just to use them in the request body to show them with swagger UI.
For example :
#RequestMapping(value = "/update/project/{id}", method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> projectUpdate(#RequestBody ObjectNode json, #PathVariable int id)
{ ... }
If I use it like this, the example will be empty on the Swagger UI page.
So as a solution, I have to do it like the following
public class CustomerCreateRequest {
#JsonProperty
private String ProjectId;
#JsonProperty
private String ProjectName;
#JsonProperty
private String ProjectDescription;
#JsonProperty
private String CustomerId;
#JsonProperty
private String CustomerName;
#JsonProperty
private String CustomerDescription;
#JsonProperty
private String BucketId;
#JsonProperty
private String API_KEY;
#JsonProperty
private String Name;
#JsonProperty
private String RedmineId;
And then I can use the model class I just created like the following.
#PostMapping(value = "/createUser")
public ResponseEntity createCustomer(#RequestBody CustomerCreateRequest requestBody)
{ ... }
Question
Is it ok to do a model class just for this purpose?
Is there a way to add an example so the UI team will have an idea of how to use it.
I know that a model class can be helpful in generating a client for UI ( like JSClient ) But is it really necessary? I mean can't we overcome this issue?
Any Answer, Suggestion, Links are appreciated, the swagger docs was not helpful in my case.
my two cents:
Is it ok to do a model class just for this purpose?
Yes, you should use a model class for your #RequestBody becouse every endpoint must have a contract to communicate the payload necessary to be consumed.
It's a good practice add the annotations like
#Parameter(description="Some description", example="{\"foo\":\"bar\"}")
#RequestBody CustomerCreateRequest requestBody
Is there a way to add an example so the UI team will have an idea of how to use it.
No, Swagger will map a POJO class with decorators such as #Schema and others. ObjectNode has not a valid representation for the use case
I know that a model class can be helpful in generating a client for UI ( like JSClient ) But is it really necessary? I mean can't we overcome this issue?
Well, in my experience use tools as Swagger have more benefits than cons. It's necessary take care about the constraints related? I think so

How to handle post and put request data validation

I have following user details model that is used in POST & PUT controllers of /user resource.
public class UserDetails {
#NotBlank
private String username;
#NotBlank
private String password;
#NotBlank
private String firstName;
#NotBlank
private String lastName;
#NotBlank
private String nic;
#NotNull
private Integer roleId;
// constructor & getters setters
}
#PostMapping("/org/employee")
public void createEmployee(#RequestBody EmployeeDetailsModel empDetails) {
employeeService.createUser(empDetails);
}
#PutMapping("/org/employee")
public void updateEmployee(#RequestBody EmployeeDetailsModel empDetails) {
employeeService.updateUser(empDetails);
}
Here, UserDetails has #NotNull & #NotBlank validations. POST would work fine because to create a user, all details are mandatory. But when updating with PUT, I don't need all properties of UserDetails to be filled.
So my questions are,
How this kind of scenarios are handled? Do we usually force clients to send all those details whether they are changed or not?
Is it possible to disable request body validation just for a particular endpoint or do I have to create separate model that looks the same but without validations?
Seeing your post I can infer that you are interested in modifying the resource
Well to do this you should to use PATCH method instead of PUT.
In PUT you need to send the entire data since it is intended for replacing the resource which is not in the case of the PATCH.
Well in case of the PUT or PATCH we need to ensure that we have an existing resource. Hence before saving it is necessary that we get the original resource from the data store. Then we can modify it with the help of the validation rules on the Entity itself.
so your code should be like.
Considering you have a repository class named as
EmployeeRepository
#PutMapping("/org/employee/{id}")
public void updateEmployee(#RequestBody EmployeeDetailsModel empDetails, #PathVariable("id") int id) {
Optional<Employee> emp = employeeRepo.findById(id);
if (emp.isPresent()) {
// update the new values using setters
// Finally update the resource.
employeeService.updateUser(empDetails);
} else {
throw new ResourceNotFoundException("Your custom msg");
}
}
The repository code should be placed inside the service method ie updateUser but I have placed it here just for demonstration.

How to implement Password validation in Spring Boot

I have a Website written in Spring Boot where you can change your password.
Now I want the user to follow some specific rules ( password length, ... ) for changing his/her password.
My problem is that I get a whole list of users and I cannot use #ValidPassword on this list.
As far as I understand is that you have to use it on fields.
So does my Controller look like:
#PostMapping
public String updateOldPassword(#ModelAttribute
#Valid UserCreationDto userTableSettings,
#RequestParam("radiobutton") String radiobuttonName, BindingResult result, Model model, Errors errors)
This is my UserCreationDto:
public class UserCreationDto {
private List<User> users;
...
And here comes my List where I use the #ValidPassword annotation, however, it is not triggered and I think that I have to move it into my UserCreationDto class but then I cannot use the List<User> anymore.
#Data
public class User {
//#SafeHtml prevents XSS ( Cross-Site Scripting )
#SafeHtml
private String username;
#ValidPassword
private String password;
private String anzeigename;
private String dienstnummer;
private long id;
private Boolean isActive;
}
I hope I described my problem as clearly as possible.
Maybe someone has a good hint for me how to solve this problem.
Thank you very much.

Spring return selected field from domain

I've the following domain and needs to return selected field in response to client. How can I achieve that using Spring?
public class Vehicle {
private String vehicleId;
private Long dateCreated;
private String ownerId;
private String colourCode;
private String engineNumber;
private String transmission;
//getters & setters
}
My objective is to return only colourCode and transmission fields to client request. I've read about DTO and seems like I can achieve my objective with DTO but I don't find any good example how to implement it. Is DTO is the correct way to achieve my objective ?
Basically you just create VehicleDTO class with parameters you need
public class VehicleDTO {
private String colourCode;
private String transmission;
//getters and setters
}
and then in your code you construct VehicleDTO from your Vehicle class. Fortunately, we have BeansUtils class from Spring, that uses reflection to copy properties of one object to another, because you do not want to repeat logic for copying properties for every object. So it would be something like:
BeanUtils.copyProperties(v1, dto);
At the end your return VehicleDTO in your response instead of Vehicle
You can return IVehicle interface which exposes your properties of choice
public interface IVehicle {
String getTransmission();
String getColourCode();
}
and your Vehicle implents it
public class Vehicle implements IVehicle{ }
There are various ways you can achieve what you want.
You can add relevant usecase / APi specific DTO for the resource.
e.g. If your API return the vehical general details you may want to expose some level of details,
public class VehicleDetailsDTO {
private String colourCode;
private String transmission;
private String engineNumber; //more
//getters and setters
}
You can then either use BeanUtils or Dozzer to convert your Vehical resource to transportable object like your DTO.
BeanUtils : http://commons.apache.org/proper/commons-beanutils/
Dozzer : http://dozer.sourceforge.net/documentation/mappings.html
Assuming you use JSON as output format and Jackson as serialization engine (default in Spring MVC), you can tell Jackson to not serialize null properties. Now you just need to populate the properties you need and can return the original business object.

handle nest array<object> in #ModelAttribute in Spring Controller

I have the following 2 objects :
public class Form {
private Long id;
private String name;
private ArrayList<FormField> fields;
...
}
public class FormField {
private Long id;
private String name;
...
}
Is it possible to receive the whole data in
public Result add(#ModelAttribute Form form)
?
The logical thing I thought of was sending the parameters in the following way
id:1
name:testdf
fields.id:1
fields.id:2
fields.id:3
fields.id:
fields.name:field 1
fields.name:field 2
fields.name:field3
But this doesn't seem to be working, Any idea how to handle a request like this ?
I'm trying to avoid custom renderers or manually parsing the HTTPRequest to fill my object.
Thanks

Resources