Card 04/ 06

GotchaDifficulty: Intermediate1 min

@RestController vs @Controller: When a Returned String Becomes a 404

The same method body answers hello under one annotation and 404 under the other.

@Controller and @RestController both mark a class whose methods answer web requests, but they treat a returned value differently. @RestController sends the value back as the response body; @Controller treats a returned String as the name of a view (an HTML template) to render.

Two methods with identical bodies both return the string "hello". One answers with hello, and the other answers 404:

java
@RestController
class GreetingRestController {
    @GetMapping("/rest-greeting")
    String greet() { return "hello"; }
}

@Controller
class GreetingViewController {
    @GetMapping("/view-greeting")
    String greet() { return "hello"; }
}
text
@RestController -> 200 body="hello"
@Controller -> 404 (treats "hello" as a view name to resolve)
run in a container: identical method bodies, different class annotation

In a templated application, "hello" would resolve to a template such as hello.html. With no template engine configured, Spring has nothing to render "hello" into, and the request ends in a 404.

@RestController is @Controller with @ResponseBody added to every method, and @ResponseBody is what changes the interpretation: the return value becomes the response body itself.

The mistake is easy to make when a method moves between classes, and costly because the application starts and the method looks right; only the call itself fails.

For a JSON or text API, use @RestController. Use @Controller only when methods return template names, and if one method in such a class needs to return data, put @ResponseBody on that method alone.