DEV Community

DevCorner
DevCorner

Posted on

API Design Best Practices in Spring Boot 2

Designing RESTful APIs is a crucial aspect of building scalable and maintainable applications. In this blog, we will explore best practices for API design using Spring Boot, with practical examples and code snippets.


1. Accept and Respond with JSON

By default, Spring Boot APIs should accept and respond with JSON.

Implementation:

@RestController
@RequestMapping(value = "/users", produces = MediaType.APPLICATION_JSON_VALUE)
public class UserController {
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        User user = userService.getUserById(id);
        return ResponseEntity.ok(user);
    }
}
Enter fullscreen mode Exit fullscreen mode

2. Use Nouns Instead of Verbs in Endpoint Paths

Good:

  • GET /users
  • POST /users
  • DELETE /users/{id}

Bad:

  • GET /getUsers
  • POST /createUser
  • DELETE /removeUser/{id}

Following RESTful principles improves API consistency.


3. Name Collections with Plural Nouns

Example:

@GetMapping("/orders")
public List<Order> getAllOrders() {
    return orderService.getAllOrders();
}
Enter fullscreen mode Exit fullscreen mode

Use /orders instead of /order for collections.


4. Nesting Resources for Hierarchical Objects

For related entities, use nested URLs.

Example:

@GetMapping("/users/{userId}/orders")
public List<Order> getUserOrders(@PathVariable Long userId) {
    return orderService.getOrdersByUserId(userId);
}
Enter fullscreen mode Exit fullscreen mode

5. Handle Errors Gracefully and Return Standard Error Codes

Using @ControllerAdvice for global error handling:

Implementation:

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<String> handleUserNotFound(UserNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
    }
}
Enter fullscreen mode Exit fullscreen mode

6. Allow Filtering, Sorting, and Pagination

Spring Data JPA provides built-in support.

Implementation:

@GetMapping("/users")
public Page<User> getUsers(
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "10") int size,
        @RequestParam(defaultValue = "id,asc") String sort) {
    Pageable pageable = PageRequest.of(page, size, Sort.by(sort.split(",")));
    return userRepository.findAll(pageable);
}
Enter fullscreen mode Exit fullscreen mode

Pagination Response Format:

Spring Boot provides pagination metadata automatically.

{
  "content": [...],
  "pageable": {...},
  "totalPages": 5,
  "totalElements": 50,
  "size": 10,
  "number": 1
}
Enter fullscreen mode Exit fullscreen mode

7. Maintain Good Security Practices

  • JWT Authentication:
  • Rate Limiting:
  • Validation to prevent SQL Injection:

Example:

@Validated
@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
    return ResponseEntity.ok(userService.save(user));
}
Enter fullscreen mode Exit fullscreen mode

8. Cache Data to Improve Performance

Example:

@Cacheable("users")
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
    return userService.getUserById(id);
}
Enter fullscreen mode Exit fullscreen mode

9. Versioning Our APIs

Example (Path Versioning):

@RestController
@RequestMapping("/api/v1/users")
public class UserControllerV1 {
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        return ResponseEntity.ok(userService.getUserById(id));
    }
}
Enter fullscreen mode Exit fullscreen mode

Other versioning strategies include Query Parameters (/users?version=1) and Header-based versioning.


Conclusion

Following these best practices ensures robust API design, improving performance, security, and maintainability.

Would you like to explore more advanced API design topics? Let me know! 🚀

Top comments (0)