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