Spring Boot - Building REST APIs with @RestController

Spring Boot makes it very easy to build RESTful web services. The @RestController annotation combines @Controller and @ResponseBody so that every method return value is automatically serialised to JSON and written to the HTTP response.

Contents

GET endpoint

Use @GetMapping to handle HTTP GET requests. Path variables are injected with @PathVariable and query parameters with @RequestParam.

Java
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/api/products")
public class ProductController {

    private final ProductService productService;

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

    // GET /api/products
    @GetMapping
    public List<Product> getAllProducts() {
        return productService.findAll();
    }

    // GET /api/products/42
    @GetMapping("/{id}")
    public Product getProduct(@PathVariable Long id) {
        return productService.findById(id);
    }

    // GET /api/products/search?category=electronics&page=0
    @GetMapping("/search")
    public List<Product> search(@RequestParam String category,
                                  @RequestParam(defaultValue = "0") int page) {
        return productService.findByCategory(category, page);
    }
}

POST endpoint

@PostMapping handles HTTP POST. Use @RequestBody to deserialise the JSON request body into a Java object.

Java
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/products")
public class ProductController {

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)   // returns 201
    public Product createProduct(@RequestBody Product product) {
        return productService.save(product);
    }
}

PUT and DELETE endpoints

Java
@RestController
@RequestMapping("/api/products")
public class ProductController {

    // PUT /api/products/42
    @PutMapping("/{id}")
    public Product updateProduct(@PathVariable Long id,
                                  @RequestBody Product updated) {
        return productService.update(id, updated);
    }

    // DELETE /api/products/42
    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)   // returns 204
    public void deleteProduct(@PathVariable Long id) {
        productService.delete(id);
    }
}

ResponseEntity for fine-grained control

Use ResponseEntity<T> when you need full control over the HTTP status code, headers, and body.

Java
import org.springframework.http.ResponseEntity;
import java.net.URI;

@RestController
@RequestMapping("/api/products")
public class ProductController {

    @GetMapping("/{id}")
    public ResponseEntity<Product> getProduct(@PathVariable Long id) {
        return productService.findByIdOptional(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());   // 404
    }

    @PostMapping
    public ResponseEntity<Product> create(@RequestBody Product product) {
        Product saved = productService.save(product);
        URI location = URI.create("/api/products/" + saved.getId());
        return ResponseEntity.created(location).body(saved);  // 201 + Location header
    }
}