Spring Boot Basics: Build Your First Java Web App
Request Bodies and Validation
In this lesson you will
- Receive JSON with @RequestBody and a record
- Add validation annotations and trigger them with @Valid
- Return 201 Created with a Location header
Introduction
When a client creates data, it sends a JSON body. Spring converts it into a Java object, and Jakarta Bean Validation checks it. This lesson is written for Spring Boot 4.1.2 and the code was not compiled or run here. To use validation, add the Validation dependency (spring-boot-starter-validation) when you generate the project.
A request record with rules
Java
package com.example.demo.book;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public record CreateBookRequest(
@NotBlank @Size(max = 100) String title,
@Min(1450) @Max(2100) int year) {}@NotBlank: not null, and not empty or only spaces.@Size(max = 100): at most 100 characters.@Minand@Max: numeric limits.
Other common annotations include @NotNull, @Email, @Pattern, @Positive and @Past.
Using it in a controller
Java
import java.net.URI;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@PostMapping
public ResponseEntity<Book> create(@Valid @RequestBody CreateBookRequest request) {
long id = nextId.getAndIncrement();
Book book = new Book(id, request.title(), request.year());
books.put(id, book);
return ResponseEntity
.created(URI.create("/books/" + id))
.body(book);
}@RequestBodytells Spring to read the JSON body and build aCreateBookRequest.@Validruns the validation. If a rule fails, Spring rejects the request with 400 Bad Request before your method body runs.ResponseEntity.created(uri)sets status 201 and the Location header, the address of the new resource.
Sending:
Terminal
curl -X POST http://localhost:8080/books \
-H "Content-Type: application/json" \
-d '{"title":"Emma","year":1815}'is expected to return 201 with a JSON body such as {"id":2,"title":"Emma","year":1815}. Sending an empty title or a year of 1000 is expected to return 400.
Make sure the client sends the Content-Type: application/json header. Without it, Spring may answer 415 Unsupported Media Type.
Quick quiz
What does @Valid do on a @RequestBody parameter?
Separate request and response types
Notice CreateBookRequest has no id, while Book does. This is deliberate:
- Clients must not choose the id.
- Later, database entities may contain fields that should never be returned. Using separate request and response records (often called DTOs, data transfer objects) keeps control over what goes in and out.
What the error looks like
By default, Spring Boot returns an error response with a status and a short message. The exact JSON shape varies by version and configuration. The intermediate course shows how to produce a consistent, clear error format for validation failures.
Validate at the boundary, and again where it matters
Validation annotations protect your API's inputs. Business rules, such as "a user cannot borrow more than 5 books", belong in your service code. Never rely only on client-side checks, since clients can be bypassed.
Try it yourself
Add a PUT /books/{id} endpoint that replaces a book using the same request record, returning 404 if the book does not exist. Add a rule that the title must contain at least 2 characters.
Summary
- @RequestBody converts JSON into an object, and @Valid applies Jakarta Validation annotations like @NotBlank and @Min.
- Return 201 Created with a Location header when a resource is created.
- Use separate request and response types, and validate at the boundary and in business logic.
Lesson complete
+20 XP
Nice work. Keep going while it is fresh.
Sources and further reading