Skip to main content

3.2 REST Controllers & Endpoint Mapping

← Back to Chapter 3: REST API & Web Layer

Building RESTful services requires clear URL design, correct HTTP verb semantics, and structured controller architecture.


@Controller vs @RestController​

Feature@Controller@RestController
Primary Use CaseUsed mainly for MVC/web pagesUsed mainly for REST APIs
Return TypeUsually returns a view/page nameUsually returns data such as JSON/XML
SerializationDoes not automatically serialize return value to JSONAutomatically serializes return value to JSON
@ResponseBodyIf you want JSON, commonly use @ResponseBody@ResponseBody is included automatically
Ecosystem / TechUsed with technologies like Thymeleaf/JSPCommonly used in Spring Boot microservices
// Traditional MVC: Returns view name resolved by ViewResolver (Thymeleaf/JSP)
@Controller
public class WebViewController {
@GetMapping("/home")
public String index(Model model) {
model.addAttribute("title", "Dashboard");
return "home"; // resolves to home.html
}
}

// Modern REST: Method return value written directly to HTTP response as JSON
@RestController // Equals @Controller + @ResponseBody on every method
@RequestMapping("/api/v1/users")
public class UserRestController {
@GetMapping("/{id}")
public UserResponse getUser(@PathVariable Long id) {
return userService.findById(id); // Jackson serializes to {"id": 1, ...}
}
}

HTTP Method Mappings & REST Semantics​

Spring MVC offers shorthand composite annotations for HTTP verbs:

AnnotationHTTP MethodIdempotent?Safe?Typical REST Usage
@GetMappingGETYesYesRetrieve a resource or collection
@PostMappingPOSTNoNoCreate a new resource or execute non-idempotent action
@PutMappingPUTYesNoCompletely replace/overwrite an existing resource
@PatchMappingPATCHNoNoPartially update specific fields of a resource
@DeleteMappingDELETEYesNoDelete a resource
@RestController
@RequestMapping("/api/v1/products")
public class ProductController {

private final ProductService productService;

public ProductController(ProductService productService) {
this.productService = productService;
}

@GetMapping
public List<ProductDTO> listAll() {
return productService.getAll();
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public ProductDTO create(@Valid @RequestBody CreateProductRequest req) {
return productService.create(req);
}

@PutMapping("/{id}")
public ProductDTO replace(@PathVariable Long id, @Valid @RequestBody UpdateProductRequest req) {
return productService.replace(id, req);
}

@PatchMapping("/{id}")
public ProductDTO partialUpdate(@PathVariable Long id, @RequestBody Map<String, Object> fields) {
return productService.patch(id, fields);
}

@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(@PathVariable Long id) {
productService.delete(id);
}
}

Indempotency​

Idempotent means: If you perform the same request multiple times, the final state of the server remains the same as after performing it once.

HTTP MethodIdempotent?Why?Example
GET✅ YesIt only retrieves data and does not change server state.GET /users/10
POST❌ NoRepeating it can create multiple resources or perform the operation multiple times.POST /users → may create multiple users
PUT✅ YesRepeating the same request updates/replaces the resource with the same data.PUT /users/10
PATCH⚠️ Usually NoIt partially updates a resource, and repeating the operation may cause different results depending on the operation.PATCH /account → increment balance
DELETE✅ YesDeleting the same resource multiple times results in the resource remaining deleted.DELETE /users/10
HEAD✅ YesLike GET but returns headers without the response body; it doesn't change server state.HEAD /users/10
OPTIONS✅ YesIt retrieves supported communication options and doesn't modify the resource.OPTIONS /users