@RestController vs @Controller + @ResponseBody
Fast recall
Quick revision
Core answer
Awareness of Spring's composed annotations and how they affect the response-writing pipeline.
Thinking they are completely interchangeable in all scenarios — @Controller is still needed when a class mixes REST endpoints with view-returning methods.
Explain how @ResponseBody triggers HttpMessageConverter selection and mention that the same class-level annotation propagates to all methods, so mixing JSON and view responses in one class requires explicit @ResponseBody per method with @Controller.
Interview-ready guide
Interview answer
@RestController is the standard for building REST APIs in Spring. Understanding what the annotation actually does — and why @Controller still exists — prevents subtle bugs when views and APIs coexist.
What the annotations do
@Controller— marks the class as a Spring MVC handler; return values are interpreted as view names (Thymeleaf/JSP template paths) by default@ResponseBody— tells Spring to write the return value directly to the HTTP response body viaHttpMessageConverter, not interpret it as a view name@RestController— composed annotation that applies both; every method in the class writes its return value to the response body
When to use `@Controller` instead
- Server-side rendering with Thymeleaf or JSP — returning a view name that the template engine resolves
- Mixed controllers that serve both HTML pages and REST endpoints — use
@ResponseBodyper method on the REST endpoints
`ResponseEntity
- Return
ResponseEntity.ok(body)for200,ResponseEntity.created(uri).body(dto)for201 CreatedwithLocationheader,ResponseEntity.noContent().build()for204 - Use when you need to set custom headers or status codes not expressible with
@ResponseStatus
@RestController vs @Controller + @ResponseBody
Direct Answer
@RestController is a composed annotation that combines @Controller and @ResponseBody. It marks the class as a Spring component and tells Spring to write every method's return value directly to the HTTP response body via HttpMessageConverter rather than resolving a view name.
Code Example
// ---------------- Option A: classic @Controller + @ResponseBody -------------
// @Controller by default returns a VIEW NAME that goes through a ViewResolver
// (Thymeleaf, JSP, etc.). Add @ResponseBody on every handler that should
// instead serialize the return value straight to the response body.
@Controller
@RequestMapping("/v1/users")
class UsersController {
// HTML view — return value is a template name ("users/list")
@GetMapping
String listPage(Model model) {
model.addAttribute("users", service.list());
return "users/list"; // resolved by ViewResolver
}
// REST endpoint on the same controller — @ResponseBody needed per method
@GetMapping("/{id}")
@ResponseBody
UserDto getOne(@PathVariable long id) {
return service.get(id); // Jackson -> JSON
}
@PostMapping
@ResponseBody
@ResponseStatus(HttpStatus.CREATED)
UserDto create(@RequestBody @Valid CreateUserRequest req) {
return service.create(req);
}
}
// ---------------- Option B: @RestController --------------------------------
// @RestController is @Controller + @ResponseBody at the CLASS level.
// Every method's return value is written to the body — no ViewResolver.
@RestController
@RequestMapping("/v1/users")
class UsersRestController {
@GetMapping
List<UserDto> list() {
return service.list();
}
@GetMapping("/{id}")
UserDto getOne(@PathVariable long id) {
return service.get(id);
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
UserDto create(@RequestBody @Valid CreateUserRequest req) {
return service.create(req);
}
}
// ---------------- Rule of thumb ---------------------------------------------
// * Pure JSON/XML API -> @RestController (the 2026 default for REST)
// * Mixed HTML + JSON -> @Controller, add @ResponseBody per method,
// or split into two controllers
// * Error handling -> Use @RestControllerAdvice (auto-@ResponseBody)
// with @ControllerAdvice when you still return views.
//
// Gotcha: @RestController + spring-boot-starter-thymeleaf still works, but
// returning a String is a body (not a view name). To render templates from
// a @RestController you must return a ModelAndView or use @Controller.
Common Mistakes & Pitfalls
Thinking they are completely interchangeable in all scenarios — @Controller is still needed when a class mixes REST endpoints with view-returning methods.
Check your understanding
Answer these without looking back at the article.
- How does Spring decide which HttpMessageConverter to use when a method returns a Java object?
- Can you return a view from a @RestController method? How?
- What happens if no HttpMessageConverter supports the requested Accept type?
Related interview prep categories
1Want a guided curriculum order?
These modules are also sequenced in our flagship backend interview track — open it when you prefer an ordered path instead of browsing by topic.