Spring Boot: From Basics to Production · Building REST APIs with Spring MVC

REST Controllers and Response Handling

Map HTTP endpoints, return proper status codes and headers.

@RestController classes map HTTP requests with @GetMapping, @PostMapping, @PutMapping, @PatchMapping and @DeleteMapping. Return DTOs (serialized to JSON by Jackson) or ResponseEntity when you need control over status codes and headers (e.g., 201 Created with a Location). Keep controllers thin: translate HTTP to service calls.

@RestController
@RequestMapping("/api/v1/products")
class ProductController {
    private final ProductService products;
    ProductController(ProductService products) { this.products = products; }

    @GetMapping("/{id}")
    ProductResponse get(@PathVariable long id) {
        return products.get(id);                       // 404 handled by exception handler
    }

    @PostMapping
    ResponseEntity<ProductResponse> create(@Valid @RequestBody CreateProductRequest request) {
        ProductResponse created = products.create(request);
        URI location = URI.create("/api/v1/products/" + created.id());
        return ResponseEntity.created(location).body(created);
    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    void delete(@PathVariable long id) {
        products.delete(id);
    }
}

Common pitfalls

  • Returning JPA entities directly (lazy-loading errors, leaking internal fields).
  • Business logic in controllers.
  • Always returning 200, even for creations and deletions.

Key points

  • Thin controllers
  • ResponseEntity for status/headers
  • 201 + Location for creations

Further reading: Spring MVC: Annotated controllers

Practice questions

Why shouldn't controllers return JPA entities?

Answer

Entities may trigger lazy loading outside transactions, create infinite recursion in bidirectional relations, and expose internal fields; DTOs define a stable API contract.

How do you return 201 with a Location header?

Answer

Return ResponseEntity.created(uri).body(dto) from the POST handler.

Open in the app to mark lessons complete, take notes and track your progress.