Here my controller:
#PutMapping("{id}")
public Mono<QdCFPresenter> save(
Long id,
#RequestBody #Valid #NotNull QdCFPresenter qdcf
) {
return this.qdcfService.store(qdcf);
}
I need to validate that id and qdcf.id are equals.
The way I need to accomplish that is using javax.validation.
We have all validation rules all encapsulated using javax.validation validations.
For example:
public class QdCFPresenter {
private Long id;
#NotNull
private Long codi;
}
So, is there any way to get it USING javax.validation validations?
I need to validate that id and qdcf.id are equals.
I would disagree with this statement.
I would suggest to separate the concepts and have 3 different classes:
an incoming request DTO (QdCFPresenter in your case), it shouldn't contain id as it is a part neither of POST nor PUT request
a domain model (with id and code)
an outgoing response DTO (also with id and code)
Two last ones look similar but have different responsibilities. The response DTO is your contract with consumers, it could maintain its documentation and so on. The domain model is your internal thing and shouldn't be exposed to be able to evolve if required.
And the incoming request DTO is a blueprint for the creation or modification. You shouldn't require it to have id at all.
Related
I am developing my first RESTful API from scratch and with Spring Boot.
I have already created the endpoints, models and JPA repositories for "standalone" entities. But now that I started linking them together and after doing some research I got to the conclusion that I may have to create DTOs. I don't think everytime I'm creating a new Order with a POST request I should make the client send the whole Customer and Employee objects inside the request as nested objects of Order (if I am also wrong in this please let me know). I am thinking about creating a DTO by just replacing the class relations with just IDs.
This is how my entity is currently defined:
#Data
#Entity
#Table(name = "Orders")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#NotBlank
#NotNull
private String description;
#NotBlank
#NotNull
private Status status;
#NotNull
#ManyToOne
#JoinColumn(foreignKey = #ForeignKey(name = "employee_id_fk"))
private Employee employee;
#NotNull
#ManyToOne
#JoinColumn(foreignKey = #ForeignKey(name = "customer_id_fk"))
private Customer customer;
protected Order() {}
public Order(String description) {
this.description = description;
this.status = Status.IN_PROGRESS;
}
}
And my endpoint (this is what I must change):
#PostMapping("/orders")
ResponseEntity<EntityModel<Order>> createOrder(#Valid #RequestBody Order order) {
order.setStatus(Status.IN_PROGRESS);
Order newOrder = repository.save(order);
return ResponseEntity
.created(linkTo(methodOn(OrderController.class).getOrder(newOrder.getId())).toUri())
.body(assembler.toModel(newOrder));
}
Now, how should I validate the requests with this format?
Previously, as you can see, I would simply use #Valid and it would automatically get validated when the endpoint is called against the Order model. However, if I create the DTO, I would have to validate the DTO with the same methodology and duplicate all the annotations from its model (#NotNull, #NotBlank, etc.). Maybe I should validate the entity model after mapping it from the DTO but I don't know how straightforward that would be and whether that is a good practice of validating requests. I also can't remove the validations from the entity model because I'm using Hibernate to map them to tables.
Great questions!
I don't think everytime I'm creating a new Order with a POST request I should make the client send the whole Customer and Employee objects inside the request as nested objects of Order (if I am also wrong in this please let me know).
You're right. It's not because we can save bits and bytes (as it may look like), but because the lesser information you can ask from the client, the better the experience he/she would get (whether it's an external integrator or front-end/back-end application within the same company). Fewer amounts of data to encompass = easier to comprehend and less room for an error. It also makes your API cleaner from the design perspective. Is it possible to process your request without the field? Then it shouldn't be in your API.
Now, how should I validate the requests with this format? Previously, as you can see, I would simply use #Valid and it would automatically get validated when the endpoint is called against the Order model. However, if I create the DTO, I would have to validate the DTO with the same methodology and duplicate all the annotations from its model (#NotNull, #NotBlank, etc.).
You can also use #Valid to kick in validation for DTO inside the controller within the method mapped to endpoint. But as you mentioned correctly, all validated fields within DTO should be annotated with #NotNull, #NotBlank, etc. As a solution, to the "duplication" problem, you can create a base class and define all validations in there and inherit DTO and Entity from it. But please, don't do that!
Having the same fields and validation rules within DTO and Enity isn't considered duplication since they are separate concepts and each one of serves its specific purpose within its layer (DTO - top tier, Entity - most often lowest, Data tier). There are a lot of examples demonstrating it (e.g. here and here)
Maybe I should validate the entity model after mapping it from the DTO but I don't know how straightforward that would be and whether that is a good practice of validating requests.
It's a best practice to validate the request and a lot of projects are following it. In your example, it's very straightforward (direct mapping from DTO to Entity), but very often you would have a service layer that does some business logic before handing it off to a data layer (even in your example I recommend moving out your code from controller to a service layer). You don't want malformed request pass beyond the controller to handle it later with excessive if statements, null checks (that leads to a defensive code that's hard to follow and it's also error-prone).
Another note: you shouldn't sacrifice client experience and tell them or force yourself to add two more fields because it allows having one Object serving as DTO and Entity and simplifies development.
The last note: To map fields from DTO to Entity you can use one of the object mapper libraries.
I've a simple RESTful API based on Spring MVC using a JPA connected MySQL database. Until now this API supports complete updates of an entity only. This means all fields must be provided inside of the request body.
#ResponseBody
#PutMapping(value = "{id}")
public ResponseEntity<?> update(#Valid #RequestBody Article newArticle, #PathVariable("id") long id) {
return service.updateById(id, newArticle);
}
The real problem here is the validation, how could I validate only provided fields while still require all fields during creation?
#Entity
public class Article {
#NotEmpty #Size(max = 100) String title;
#NotEmpty #Size(max = 500) String content;
// Getters and Setters
}
Example for a partial update request body {"content": "Just a test"} instead of {"title": "Title", "content": "Just a test"}.
The actual partial update is done by checking if the given field is not null:
if(newArticle.getTitle() != null) article.setTitle(newArticle.getTitle());
But the validation of course wont work! I've to deactivate the validation for the update method to run the RESTful service. I've essentially two questions:
How can I validate only a "existing" subset of properties in the
update method while still require all fields during creation?
Is there a more elegant way for update partially then checking for
null?
The complexity of partial updates and Spring JPA is that you may send half of the fields populated, and even that you will need to pull the entire entity from the data base, then just "merge" both entity and the pojo, because otherwise you will risk your data by sending null values to the database.
But merging itself is kind of tricky, because you need to operate over each field and take the decision of either send the new value to the data base or just keep the current one. And as you add fields, the validation needs to be updated, and tests get more complex. In one single statement: it doesn't scale. The idea is to always write code which is open for extension and closed for modifications. If you add more fields, then the validation block ideally doesn't need to change.
The way you deal with this in a REST model, is by operating over the entire entity each time you need. Let's say you have users, then you first pull a user:
GET /user/100
Then you have in your web page the entire fields of user id=100. Then you change its last name. You propagate the change calling the same resource URL with PUT verb:
PUT /user/100
And you send all the fields, or rather the "same entity" back with a new lastname. And you forget about validation, the validation will just work as a black box. If you add more fields, you add more #NotNull or whatever validation you need. Of course there may be situations where you need to actually write blocks of code for validation. Even in this case the validation doesn't get affected, as you will have a main for-loop for your validation, and each field will have its own validator. If you add fields, you add validators, but the main validation block remains untouchable.
I'm designing a REST service and am running into the issue that for a given object, I have multiple "states".
The object as it arrives on the initial POST operation.
The Object I store in our DB
The Object I return on a GET
The Object I expect on a PATCH
e.g.
class MyObject {
// Unwanted on POST
// Required on PATCH
// Included on GET
#JsonProperty("id")
private UUID id;
// Everywhere
#NonNull
#JsonProperty("name")
private String name;
// Field I need for internal processing but don't want included in REST.
private AuditTrail stuff;
#JsonCreator
#Builder
public MyObject(...) { ... }
}
...
#Get
public ResponseEntity myFunction(HttpServletRequest request,
#RequestBody #Valid MyObject requestBody) {
...
}
The issue I am running into is that on POST, when the id is omitted, the deserialization fails. I got around it using #JsonIgnoreProperties(), but now on PATCH, where I do want the id present, things work if it is omitted.
Another alternative we toyed with was to have two objects. The first one with the common fields for POST and the other extending from it with the rest, but it feel messy, especially as we deal with objects more complex than the simple example.
It's not actually a problem since I validate and sanitize inputs anyway, but I was wondering if there is a clean way in Jackson to solve this issue.
If you are planning a rest service then you don't need the id in the body anyway. The id will come from the url as a pathvariable:
POST myobjects
GET myobjects/{id}
PATCH myobjects/{id}
How can I prevent user from entering HTML or Java script tags in input type in Spring MVC? There should be a server side validation. I am working on a project with thousands of JSPs and controllers. How can I do this?
If you want a server side solution, you could implement a redirect filter that eliminates everything that contains javascript tags and javascript code. Another way is to check the input values in the controller's method that is associated with it.
You probably have to redesign a few things. First, you should always validate the user input twice: once client-side, once server-side.
Thus, you will need to validate the user input in your JavaScript code (using a Regexp probably), and to validate it again in your Java code.
If your application follow the usual design patterns, your controller receives a DTO as a parameter to the entry-point. There you can use the #Valid annotation and add all the necessary rules on the fields of your DTO (using javax.validation annotations).
While there may be many possible answers, one of them is using JSR 303 validator framework.
You can include hibernate validator to use JSR 303 framework.
First step is applying different type of constraint on your class. For example
example taken from : Hibernate Validator - Reference - 1.2. Applying constraints
package org.hibernate.validator.referenceguide.chapter01;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class Car {
#NotNull //manufacturer must never be null
private String manufacturer;
#NotNull
#Size(min = 2, max = 14) //licensePlate must never be null and must be between 2 and 14 characters long
private String licensePlate;
#Min(2)
private int seatCount; //seatCount must be at least 2
//getters and setters ...
}
Now in your controller, use #Valid annotation to validate your car object and also pass a BindingResult parameter, that will validate whether this object is valid or not
#Controller
#RequestMapping("/car")
public class CarController {
#RequestMapping(value = "/newcar", method = RequestMethod.POST)
public String addCustomer(#Valid Car car, BindingResult result) {
if (result.hasErrors()) {
//car data is not valid, enter data again
return "AddNewCar.jsp";
} else {
//save car logic here
return "CarSavedSuccessfully.jsp";
}
}
}
I'm looking for a way to export some JPA entities to a REST API, but instead of sending the whole entity every time I want to share just some specific fields depending of the entry point. Here's a small example:
Say we have an Author class with few fields:
#Entity
public class Author implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = SEQUENCE)
private Long id;
#NotNull
#Size(min = 1, message = "{required.field}")
private String name;
#NotNull
#Size(min = 1, message = "{required.field}")
private String country;
private LocalDate birthDate;
// getters and setters
}
And say we have this REST service (just two methods):
#Path("authors")
public class AuthorREST {
#Inject
private AuthorBC bc;
#GET
#Produces("application/json")
public List<Author> find(#QueryParam("q") String query) throws Exception {
List<Author> result;
if (Strings.isEmpty(query)) {
result = bc.findAll();
} else {
result = bc.find(query);
}
return result;
}
#GET
#Path("{id}")
#Produces("application/json")
public Author load(#PathParam("id") Long id) throws Exception {
Author result = bc.load(id);
if (result == null) {
throw new NotFoundException();
}
return result;
}
}
Now, this way, I'll always have the 4 fields when my API is called.
I understand that if I use Jackson I can set an #JsonIgnore to fields I want to ignore, and they will always be ignored.
But what if I want that, in some cases, my whole entity is returned by one service, and in other service (or other method in the same service), only 2 or 3 fields are returned?
Is there a way to do it?
#JsonView and mix-in
You already know you can use annotations such as #JsonIgnore and #JsonIgnoreProperties to make Jackson ignore some properties.
You also could check the #JsonView annotation. For some details on how to use #JsonView with JAX-RS, have a look here.
If modifying the JPA entities is not an option, consider mix-in annotations as described in this answer.
Data Transfer Object
Data Transfer Object (DTO) is a pattern that was created with a very well defined purpose: transfer data to remote interfaces, just like webservices. This pattern fits very well in REST APIs and using DTOs you'll have more flexibility in the long run. You can have tailored classes for your needs, once the REST resource representations don't need to have the same attributes as the persistence objects.
To avoid boilerplate code, you can use mapping frameworks such as MapStruct to map your REST API DTOs from/to your persistence objects.
For details on the benefits of using DTOs, check the following answers:
Why you should use DTOs in your REST API
Using tailored classes of request and response
To give better names to your DTOs, check the following answer:
Giving meaningful names to your DTOs
If you want to decouple the parsing from your JPA entities and return only certain attributes you can always use Mixins for this purpose.
http://www.cowtowncoder.com/blog/archives/2009/08/entry_305.html
https://github.com/FasterXML/jackson-docs/wiki/JacksonMixInAnnotations
One more thing. If you want things to be dynamic in one service to return one representation in another to return another representation. Your option is to write a custom JSON serializer!
Check this post for how to create a customer serializer:
How do I use a custom Serializer with Jackson?
For myself I found it quite suitable to use #JsonView annotation. So you can define fields to be rendered in specific view. You can find more info here http://wiki.fasterxml.com/JacksonJsonViews
I think you can write a custom MessageBodyWriter using Jersey framework and you can control the response payload the way you want. Here you have to write few lines of code in-order to manage the response payload. For more information please visit https://jersey.java.net/documentation/latest/message-body-workers.html#d0e6826
I would use Spring Data REST and then use the ApiModel annotation to hide the attributes you do not want exposed.