Capstone: A Complete REST API

Everything comes together: a CRUD REST API with a controller → service → repository → JPA flow, validation , error handling , security , and tests — the anatomy of a production Spring Boot service.

Learn Capstone: A Complete REST API in our free Java course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…

Part of the free Java course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

This capstone draws on the whole track: dependency injection , security , testing , and containerization . Skim any you're unsure of first.

💡 Analogy: A REST API runs like a restaurant. The waiter (controller) takes your order, checks it makes sense ( validation ), and never cooks anything themselves. They pass it to the chef (service), who knows the recipes and the rules ( business logic ). The chef fetches ingredients from the pantry (repository / JPA / database). The doorman (security) checks who may enter and which tables they can use. If something's wrong — no such dish — the manager ( @RestControllerAdvice ) sends a polite, consistent message back (a 404), not chaos. And the health inspectors ( tests ) visit regularly to make sure every station does its job.

Clear roles, clean hand-offs, and consistent responses — that's a well-built API.

Each layer has one job: the controller handles HTTP, the service holds logic, the repository handles data. The plain-Java model below shows the flow — including a missing resource becoming a 404.

Reject bad input with a 400 before it reaches your logic, and turn missing resources into a 404 . Spring uses @Valid + Bean Validation and @RestControllerAdvice ; the demo hand-rolls the same idea.

Now the real thing: a @RestController delegating to a @Service backed by a Spring Data JpaRepository , with @Valid for validation and @RestControllerAdvice for centralized error handling.

A stateless SecurityFilterChain guards the API, and @WebMvcTest + MockMvc verify the controller — including the 404 path — with the service mocked.

Answer: the service layer — controllers stay thin (HTTP) and repositories stay focused on data access.

Answer: 400 Bad Request — triggered by @Valid failing Bean Validation constraints.

Answer: throw a not-found exception and map it with @ExceptionHandler in a @RestControllerAdvice .

🎯 YOUR TURN — A Service Lookup with 404

Complete get(id) so a missing id throws (the controller would map it to 404).

🧩 MINI-CHALLENGE — A Full Create Flow

Validate the request, then persist and return 201 with an id, or return 400 with the errors.

You've assembled a complete REST API: a controller → service → repository → JPA flow with validation, centralized error handling, stateless security, and a layered test strategy — and you know how to monitor, cache, and containerize it. That's the full anatomy of a production Spring Boot service.

Congratulations on finishing the Spring Boot & Enterprise Java track. Keep building — the best way to cement these ideas is to ship a small API of your own.

Practice quiz

In the classic layered architecture, which layer talks to the database?

  • Controller
  • Service
  • Repository
  • DTO

Answer: Repository. The repository (data access) layer is responsible for persistence; the service orchestrates and the controller handles HTTP.

What is the controller layer responsible for?

  • Persisting entities
  • Handling HTTP requests/responses and delegating to the service
  • Defining the database schema
  • Hashing passwords

Answer: Handling HTTP requests/responses and delegating to the service. Controllers map HTTP to method calls, validate input, and delegate business logic to the service layer.

Where does business logic belong in this design?

  • The controller
  • The repository
  • The service layer
  • The entity getters

Answer: The service layer. The service layer holds business rules and coordinates repositories, keeping controllers thin and repositories focused on data.

Which annotation triggers Bean Validation on a request body?

  • @Valid
  • @Cacheable
  • @Transactional
  • @Bean

Answer: @Valid. Annotating a @RequestBody parameter with @Valid runs Bean Validation constraints like @NotBlank and @Size.

What is a good way to return a 404 when a resource is missing?

  • Return null
  • Log and continue
  • Return an empty 200
  • Throw an exception handled by @ExceptionHandler/@ControllerAdvice mapping to 404

Answer: Throw an exception handled by @ExceptionHandler/@ControllerAdvice mapping to 404. Throw a not-found exception and map it to HTTP 404 via @ExceptionHandler or @ControllerAdvice for consistent error handling.

Which HTTP status best fits a successful resource creation?

  • 200 OK
  • 201 Created
  • 204 No Content
  • 400 Bad Request

Answer: 201 Created. 201 Created signals a new resource was created, typically with a Location header pointing to it.

@ControllerAdvice is used to...

  • create beans
  • configure caching
  • centralize cross-cutting exception handling for controllers
  • define entities

Answer: centralize cross-cutting exception handling for controllers. @ControllerAdvice (or @RestControllerAdvice) centralizes exception handling and other advice across controllers.

To slice-test only the web layer of this API you would use...

  • @DataJpaTest
  • @WebMvcTest with MockMvc and @MockBean
  • @SpringBootTest only
  • no annotation

Answer: @WebMvcTest with MockMvc and @MockBean. @WebMvcTest loads just the controller; MockMvc drives requests and @MockBean stubs the service.

In a secured REST API, a stateless token is typically sent as...

  • a query string password
  • a hidden form field
  • an X-Powered-By header
  • Authorization: Bearer <jwt>

Answer: Authorization: Bearer <jwt>. Stateless APIs carry a JWT in the Authorization header as a Bearer token, validated by a security filter.

Why map JPA entities to DTOs at the API boundary?

  • To slow responses
  • To decouple the API contract from the persistence model and avoid leaking internals
  • Because entities can't be serialized
  • To skip validation

Answer: To decouple the API contract from the persistence model and avoid leaking internals. DTOs keep the external contract stable and prevent exposing or over-binding internal entity fields.