What Is a REST Controller in Spring Boot?
A REST controller is a Spring-managed class that exposes HTTP endpoints and returns data (usually JSON) rather than a view name. Spring Boot provides the @RestController annotation, which is a convenience annotation combining @Controller and @ResponseBody, so every method's return value is automatically serialized into the HTTP response body instead of being resolved to a template.
Cricket analogy: Think of a REST controller like the third umpire's review station: a request comes in (the on-field appeal), the controller processes it against the rules, and sends back a clear decision (JSON verdict) rather than a vague gesture.
@RestController vs @Controller
@Controller alone is meant for MVC applications where methods typically return a view name resolved by a ViewResolver (e.g., a Thymeleaf template). If you need a mix of view-returning and JSON-returning methods in the same class, you can keep @Controller and annotate individual methods with @ResponseBody. For pure APIs, @RestController is the standard choice because it applies @ResponseBody to every handler method automatically, removing repetitive annotations.
Cricket analogy: It's like a stadium announcer who mostly narrates the match for the crowd (@Controller returning views) but occasionally reads out a raw scorecard number for the broadcast feed (@ResponseBody) — @RestController is the dedicated scoreboard operator who only ever outputs raw numbers.
@RestController
@RequestMapping("/api/products")
public class ProductController {
private final ProductService productService;
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping
public List<ProductDto> listProducts() {
return productService.findAll();
}
@GetMapping("/{id}")
public ResponseEntity<ProductDto> getProduct(@PathVariable Long id) {
ProductDto product = productService.findById(id);
return ResponseEntity.ok(product);
}
}Keeping Controllers Thin
A well-built controller should focus purely on HTTP concerns: mapping routes, extracting parameters, and translating results into responses. Business logic, transaction management, and data access belong in a service layer that the controller delegates to via constructor injection. This separation keeps controllers testable with lightweight mocks and prevents HTTP-layer classes from becoming tangled with persistence or domain rules.
Cricket analogy: A good captain like Rohit Sharma sets the field and calls the shots but doesn't bowl every over himself — the controller sets up the request and delegates the real work (bowling) to specialist service classes.
Keep controller methods short. If a handler method exceeds roughly 15-20 lines or contains conditional business rules, that's usually a sign the logic belongs in a service class instead.
Returning Responses with ResponseEntity
Returning a plain object (like the List<ProductDto> above) always results in a 200 OK status with the serialized body. When you need control over the status code, headers, or to signal 201 Created, 404 Not Found, or 204 No Content, wrap the return value in a ResponseEntity<T>. This makes the controller's contract with API consumers explicit rather than relying on default status behavior.
Cricket analogy: It's like the umpire choosing between signaling a plain single (default 200 OK) versus explicitly raising both arms for a six (201 Created) — ResponseEntity lets you pick the exact signal.
Never return JPA entities directly from a controller. Lazy-loaded associations can trigger LazyInitializationException outside the persistence context, and entities often expose internal fields you don't want in your public API. Map to a dedicated DTO instead.
- @RestController combines @Controller and @ResponseBody so every method's return value is serialized directly into the response body.
- Use @Controller with per-method @ResponseBody only when a class mixes view-rendering and JSON-returning methods.
- Constructor injection of a service layer keeps controllers thin and focused on HTTP concerns only.
- Business logic, validation rules, and persistence access belong in service and repository layers, not controllers.
- ResponseEntity<T> gives explicit control over status codes, headers, and the response body.
- Never expose JPA entities directly; always map to DTOs to avoid lazy-loading errors and leaking internal fields.
- Route mapping annotations like @GetMapping and @RequestMapping define the URL surface a controller class exposes.
Practice what you learned
1. What does @RestController do that plain @Controller does not?
2. Why should controllers avoid returning JPA entities directly?
3. What is the primary benefit of wrapping a return value in ResponseEntity<T>?
4. Where should business logic like calculating a discount ideally live?
5. Which injection style is recommended for wiring a service into a Spring Boot controller?
Was this page helpful?
You May Also Like
Request Mapping and Path Variables
Understand how Spring Boot maps HTTP requests to controller methods using @RequestMapping, HTTP-method shortcuts, and path variables.
Request and Response Bodies
Learn how Spring Boot serializes and deserializes JSON request and response bodies using @RequestBody, @ResponseBody, and Jackson.
Exception Handling in Spring Boot
Learn how to handle errors gracefully in Spring Boot REST APIs using @ExceptionHandler, @ControllerAdvice, and structured error responses.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics
Web DevelopmentNext.js Study Notes
JavaScript · 30 topics