REST Principles & @RestController
REST Principles & @RestController
Before writing a single annotation, it is worth understanding what REST actually is and why it became the dominant style for web APIs. REST (Representational State Transfer) is an architectural style, not a protocol or a standard. It was defined by Roy Fielding in his 2000 doctoral dissertation as a set of constraints that, when applied to a distributed system, produce desirable properties: scalability, statelessness, uniform interfaces, and easy evolvability.
Spring Boot 3 and Spring 6 give you first-class tooling to build REST APIs, but the framework cannot enforce REST semantics for you — it just makes it easy to wire HTTP verbs, paths, and serialization together. Knowing the principles is what lets you design APIs that age well rather than ones that accumulate workarounds.
The Six REST Constraints
Fielding's original dissertation lists six constraints. Three are fundamental for everyday API design:
- Uniform Interface. Clients and servers interact through a consistent interface — resources identified by URIs, manipulated through representations, with self-descriptive messages and hypermedia links. In HTTP-based REST this translates to: use nouns for resource paths (
/orders/42, not/getOrder?id=42), use the HTTP method to express the operation, and return meaningful status codes. - Statelessness. Each request must contain all information needed to process it. The server stores no session state between requests. This is why REST APIs favour tokens in headers (
Authorization: Bearer …) over server-side sessions — any instance in a cluster can handle any request. - Client-Server Separation. The client manages the UI; the server manages data and business logic. They evolve independently as long as the API contract holds. This is the boundary
@RestControllersits on.
The remaining three (Caching, Layered System, Code-on-Demand) are important at scale but less relevant when you are first structuring your controllers.
Resources, Representations, and HTTP Verbs
A resource is any named concept your API exposes: a product, an order, a user, a report. Resources are identified by URIs. A representation is the current state of that resource serialised into a format the client can consume — usually JSON, occasionally XML or CSV.
HTTP verbs carry intent:
- GET — retrieve a representation; must be safe (no side effects) and idempotent.
- POST — create a new subordinate resource or trigger an action; neither safe nor idempotent.
- PUT — replace a resource entirely; idempotent (calling it twice has the same result as calling it once).
- PATCH — partial update; not necessarily idempotent.
- DELETE — remove the resource; idempotent.
The @RestController Stereotype
In a Spring MVC application, @Controller marks a class as a web layer component and by default expects its methods to return view names. Adding @ResponseBody to a method tells Spring to write the return value directly into the HTTP response body instead of resolving a view.
@RestController is a composed annotation — it is literally @Controller + @ResponseBody applied at the class level. Every handler method in the class implicitly carries @ResponseBody. That is the only difference. The full annotation chain resolves to a Spring-managed bean in the application context, eligible for dependency injection, AOP advice, and the dispatcher servlet's request-mapping infrastructure.
When Spring Boot's auto-configuration detects spring-boot-starter-web on the classpath it registers Jackson (MappingJackson2HttpMessageConverter) as the default message converter. Jackson serialises List<ProductDto> to JSON automatically — you never write ObjectMapper boilerplate by hand in a controller.
How the Request-Response Cycle Works
Understanding the path from an incoming HTTP request to the JSON response gives you better debugging instincts:
- The embedded Tomcat servlet container receives the TCP connection and parses the HTTP request.
DispatcherServlet— the Spring MVC front controller — consults itsHandlerMappingregistry to find which controller method handles this URI and HTTP method combination.- The method is invoked. Spring resolves its parameters (path variables, query params, request body) using registered
HandlerMethodArgumentResolvers. - The return value is processed by a
HandlerMethodReturnValueHandler. Because@ResponseBodyis present, the value is passed to the negotiatedHttpMessageConverter(Jackson for JSON) which writes bytes into the response output stream. - Tomcat flushes the response to the client.
A Minimal but Complete Example
Below is a self-contained example using Spring Boot 3 with jakarta.* imports. It demonstrates the package structure, a simple DTO record, the service boundary, and the controller wired together.
With this structure in place, Spring Boot auto-discovers both beans (component scan), wires the service into the controller, and maps GET requests. The JSON serialisation of the record fields happens automatically.
@Entity class from a @RestController method leaks your database schema, can trigger lazy-loading exceptions, and makes it difficult to evolve the API independently of the data model. Always define a DTO layer — records are an excellent fit in Java 16+.
Summary
REST is an architectural style built on uniform interfaces, statelessness, and resource-oriented URIs. HTTP verbs carry semantic intent — GET, POST, PUT, PATCH, DELETE — and idempotency determines retry safety. @RestController is a composed stereotype that marks a class as both a Spring-managed controller and a direct body-writer, eliminating the need for per-method @ResponseBody. Jackson wires in automatically via Spring Boot's auto-configuration. Keep controllers thin: accept the request, delegate, return the response. The next lesson covers request mapping in detail — how to route different HTTP methods and path patterns to specific handler methods.