Validating data
You cannot trust a client: it may send an empty title, a body that is too short or broken JSON. Validation checks input data before it reaches the store. Javalin has validators for this: the bodyValidator, queryParamAsClass, pathParamAsClass and headerAsClass methods return a Validator object to which you add rules.
How a validator works
- A
...AsClassmethod orbodyValidatorcreates a validator and tries to turn the string or JSON into the required type. check(condition, "message")methods add rules.- The
get()method returns the value or throwsValidationExceptionif any rule is broken.
Javalin turns ValidationException into a 400 response with a list of errors in JSON by itself.
Checking the request body
Replace bodyAsClass in the post creation route with bodyValidator:
// src/main/java/com/example/blog/Main.java
config.routes.post("/posts", ctx -> {
NewPost data = ctx.bodyValidator(NewPost.class)
.check(p -> p.title() != null && !p.title().isBlank(), "Title is required")
.check(p -> p.body() != null && p.body().length() >= 5, "Body is too short")
.get();
ctx.status(HttpStatus.CREATED).json(store.create(data));
});Each rule receives the ready NewPost object and returns true if everything is fine. Let us send a wrong post:
curl -i -X POST http://localhost:8080/posts \
-d '{"title":"","body":"abc","author":"Oleg"}'HTTP/1.1 400 Bad Request
Content-Type: application/json
{"REQUEST_BODY":[{"message":"Title is required","args":{},"value":{"title":"","body":"abc","author":"Oleg"}},{"message":"Body is too short","args":{},"value":{"title":"","body":"abc","author":"Oleg"}}]}
Javalin checked all the rules and returned both errors at once. The REQUEST_BODY key means the error is in the request body.
Checking parameters
The same rules work with parameters. Let us limit the page size in search:
// src/main/java/com/example/blog/Main.java
int limit = ctx.queryParamAsClass("limit", Integer.class)
.check(n -> n >= 1 && n <= 50, "Limit must be from 1 to 50")
.getOrDefault(10);For ?limit=100 the server answers 400 and {"limit":[{"message":"Limit must be from 1 to 50","args":{},"value":100}]}, and without the parameter it uses 10.
Methods for getting the value
| Method | If the value is missing | If a rule is broken |
|---|---|---|
get() | 400, error NULLCHECK_FAILED | 400 |
getOrDefault(10) | The default value | 400 |
getOrNull() | null | 400 |
Common mistake
ctx.bodyAsClass does not check data: for broken JSON such as {"title":"x" without the closing brace, the client gets 500 Server Error, and the log shows JsonEOFException: Unexpected end-of-input. It looks like a server error, although the client made the mistake. With bodyValidator the same request gets the right answer:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{"REQUEST_BODY":[{"message":"DESERIALIZATION_FAILED","args":{},"value":"{\"title\":\"x\""}]}
Use bodyValidator for data that comes from a client.