Building REST APIs with Spring Boot (Controller to Response)

boot.cloud
Boot to Cloud
Published on Mar, 16 2026 3 min read 0 comments
image

In Week 2, we learned how to set up a professional Spring Boot project with Maven, YAML configs, and proper folder structure.
Now, in Week 3, it’s time to build REST APIs — the backbone of modern backend applications.

We’ll cover controllers, DTOs, validation, CRUD operations, and best practices for professional APIs.

What is a REST API?

REST (Representational State Transfer) is an architectural style for building web APIs.
A REST API lets clients (like web or mobile apps) communicate with your backend using HTTP methods.

| HTTP Method | Action | Example URL     |
| ----------- | ------ | --------------- |
| GET         | Read   | /api/users      |
| POST        | Create | /api/users      |
| PUT         | Update | /api/users/{id} |
| DELETE      | Delete | /api/users/{id} |

Step 1: Create a Simple REST Controller

In your project, create:

src/main/java/com/example/demo/controller/UserController.java

 

@RestController
@RequestMapping("/api/users")
public class UserController {

    @GetMapping
    public String getAllUsers() {
        return "List of all users";
    }

    @GetMapping("/{id}")
    public String getUserById(@PathVariable Long id) {
        return "User with ID: " + id;
    }
}

 

Key Annotations:

  • @RestController → Combines @Controller + @ResponseBody
  • @RequestMapping → Base URL for all endpoints
  • @GetMapping → Handles HTTP GET requests
  • @PathVariable → Extracts path parameters

Step 2: Create a User Entity & DTO

User Entity

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String email;

    // Getters and Setters
}

User DTO (Data Transfer Object)

public class UserDTO {
    @NotBlank(message = "Name is required")
    private String name;

    @Email(message = "Invalid email")
    private String email;

    // Getters and Setters
}

Using DTOs decouples your API input/output from your database entity, making your APIs more maintainable and secure.

Step 3: Add Validation

Add @Valid in your controller to automatically validate incoming requests:

@PostMapping
public ResponseEntity<String> createUser(@Valid @RequestBody UserDTO userDTO) {
    // Save user logic here
    return ResponseEntity.status(HttpStatus.CREATED)
                         .body("User created: " + userDTO.getName());
}
  • @RequestBody → Binds JSON request to Java object
  • @Valid → Validates DTO fields using annotations like @NotBlank, @Email

Step 4: Add Service & Repository Layers

UserRepository

@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

UserService

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public User saveUser(User user) {
        return userRepository.save(user);
    }

    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
}

Updated Controller

@Autowired
private UserService userService;

@GetMapping
public List<User> getAllUsers() {
    return userService.getAllUsers();
}

@PostMapping
public ResponseEntity<User> createUser(@Valid @RequestBody UserDTO dto) {
    User user = new User();
    user.setName(dto.getName());
    user.setEmail(dto.getEmail());

    User saved = userService.saveUser(user);
    return new ResponseEntity<>(saved, HttpStatus.CREATED);
}

Step 5: Best Practices for REST APIs

1️⃣ ResponseEntity

Always return ResponseEntity for status codes and body control.

2️⃣ DTOs

Never expose your entities directly. Always use DTOs for requests/responses.

3️⃣ Exception Handling

Use @ControllerAdvice for centralized error handling.

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<String> handleValidationError(MethodArgumentNotValidException ex) {
        return ResponseEntity.badRequest()
                             .body(ex.getBindingResult().getFieldError().getDefaultMessage());
    }
}

4️⃣ URL Naming

Use plural nouns (/users, /products) and avoid verbs (/getUsers).

Step 6: Testing the API

Use Postman / Insomnia / curl to test:

  • GET /api/users → Should return empty list or saved users
  • POST /api/users → Send JSON:
{
    "name": "Mahabubur Rahman",
    "email": "[email protected]"
}

Response should return 201 Created with the user object.

Step 7: Pagination & Sorting (Optional Advanced)

@GetMapping
public Page<User> getUsers(
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "10") int size
) {
    Pageable pageable = PageRequest.of(page, size, Sort.by("name").ascending());
    return userRepository.findAll(pageable);
}
  • Helps manage large datasets
  • Professional APIs always implement pagination

Week 3 Recap

✅ REST basics (GET, POST, PUT, DELETE)
✅ Controller setup
✅ DTOs + Validation
✅ Service & Repository layer
✅ Best practices (ResponseEntity, Exception handling, Pagination)

What’s in Next Week?

👉 Spring Boot + JPA + Hibernate: Database Made Easy

We’ll cover:

  • Relationships (OneToMany, ManyToMany)
  • JPQL vs Native queries
  • Pagination & Sorting
  • Performance tips

📌 Action Items

✔ Build your first CRUD API
✔ Implement DTO + Validation
✔ Push API to GitHub
✔ Test with Postman

0 Comments