Spring Boot Returning HTML Instead of JSON: How to Fix with @ResponseBody
Problem
When I called my Spring Boot REST endpoint, the frontend got an error:
SyntaxError: Unexpected token < in JSON at position 0My endpoint returned a List<User> but the frontend received an HTML page instead of JSON data.
Environment
- Spring Boot backend
- Angular frontend
- REST endpoint supposed to return JSON
What Happened?
I had a controller like this:
@Controllerpublic class UserController {
@GetMapping("/users") public List<User> getUsers() { return userRepository.findAll(); }}I expected JSON output like:
[ {"id": 1, "name": "John", "lastname": "Doe"}, {"id": 2, "name": "Jane", "lastname": "Smith"}]But the actual response was:
<!DOCTYPE html><html><head> <title>Error</title>...Why did Spring return HTML instead of JSON?
The Reason
The @Controller annotation tells Spring MVC that this class returns view names. Spring tries to find a template named “List<User>” or similar, and when it fails, it falls back to rendering an error page as HTML.
Without @ResponseBody, Spring treats your return value as a view reference, not as data to serialize.
│ │ ▼ ▼Returns view name Returns JSON data │ │ ▼ ▼Spring finds template Jackson serializes │ │ ▼ ▼HTML page JSON stringHow to Solve It?
There are three approaches.
Solution 1: Add @ResponseBody to method
@Controllerpublic class UserController {
@GetMapping("/users") @ResponseBody public List<User> getUsers() { return userRepository.findAll(); }}The @ResponseBody annotation tells Spring to serialize the return value directly to the response body using Jackson.
Solution 2: Use @RestController (recommended)
@RestControllerpublic class UserController {
@GetMapping("/users") public List<User> getUsers() { return userRepository.findAll(); }}@RestController combines @Controller + @ResponseBody. All methods automatically return JSON.
Solution 3: Explicit produces attribute
@Controllerpublic class UserController {
@GetMapping(value = "/users", produces = "application/json") @ResponseBody public List<User> getUsers() { return userRepository.findAll(); }}The produces attribute explicitly declares the response Content-Type.
Now the response is proper JSON:
Content-Type: application/json;charset=UTF-8Which Solution Should I Use?
└─────────────────────────┘ │ ▼┌─────────────────────────┐│ Use @RestController ││ (cleanest approach) │└─────────────────────────┘
┌─────────────────────────┐│ Mixed controller? ││ (some HTML, some JSON) │└─────────────────────────┘ │ ▼┌─────────────────────────┐│ Use @Controller + ││ @ResponseBody on JSON ││ methods │└─────────────────────────┘For a pure REST API, @RestController is the cleanest choice.
Common Mistakes
Mistake 1: Using @Controller for REST
@Controller // Returns view names by defaultpublic class ApiController { @GetMapping("/api/data") public Data getData() { // Spring tries to find "Data" template return dataService.getData(); }}Mistake 2: Double parsing in frontend
Angular HttpClient already parses JSON:
// Wrong: unnecessary double parsedata = JSON.parse(JSON.stringify(data));
// Right: Angular already parsed itthis.httpclient.get<User[]>('/api/users') .subscribe(users => { // users is already an array });Mistake 3: Not checking Content-Type
Always verify your server sends the right Content-Type:
fetch('/api/users') .then(response => { const contentType = response.headers.get('content-type'); if (!contentType?.includes('application/json')) { throw new Error('Expected JSON, got ' + contentType); } return response.json(); });Summary
In this post, I showed how to fix Spring Boot returning HTML instead of JSON. The key point is: use @RestController or add @ResponseBody to your methods. The frontend error “Unexpected token <” is a symptom—the real fix is on the server side.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments