Exception Handling, Validation & Building a Capstone Project
📂 Phase 6: Career Launch — Spring Boot, Projects, Interview Prep (Days 27–30) · JavaA professional Spring Boot API never lets a raw stack trace leak back to the client, and it never trusts incoming data blindly. Two things make an API feel production-grade: consistent global exception handling, and request validation — and combining both inside one capstone project is how you turn everything from this phase into something interview-ready.
The Problem With Default Error Responses
Without handling, an unhandled exception in Spring Boot returns a generic, unhelpful 500 error with an internal stack trace exposed — not something you want in a real API or in front of an interviewer.
Global Exception Handling with @ControllerAdvice
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(StudentNotFoundException.class)
public ResponseEntity handleNotFound(StudentNotFoundException ex) {
ErrorResponse error = new ErrorResponse("NOT_FOUND", ex.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
@ExceptionHandler(Exception.class)
public ResponseEntity handleGeneric(Exception ex) {
ErrorResponse error = new ErrorResponse("INTERNAL_ERROR", "Something went wrong");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
}
A custom exception is just a plain class extending RuntimeException:
public class StudentNotFoundException extends RuntimeException {
public StudentNotFoundException(String message) {
super(message);
}
}
Validating Incoming Data with @Valid
Bean Validation annotations on a DTO (Data Transfer Object) let Spring reject bad input automatically, before it ever reaches your service logic.
public class StudentRequestDto {
@NotBlank(message = "Name is required")
private String name;
@Email(message = "Email must be valid")
private String email;
@Min(value = 18, message = "Age must be at least 18")
private Integer age;
// Getters and setters
}
@PostMapping
public Student create(@Valid @RequestBody StudentRequestDto dto) {
return studentService.createStudent(dto);
}
Why a DTO instead of the entity directly? Exposing your JPA entity straight through the API ties your database schema to your API contract — change one and you risk breaking the other. A DTO keeps the two independent.
Common Validation Annotations
| Annotation | Checks |
|---|---|
| @NotNull | Value must not be null |
| @NotBlank | String must not be null or empty/whitespace |
| @Size(min, max) | String/collection length within range |
| Value must be a valid email format | |
| @Min / @Max | Numeric value within bounds |
Putting It All Together: The Capstone Project
By this point you have every piece needed to build one complete, interview-ready project — a Student Management REST API (or a Task Manager, if you prefer):
- Entity + Repository + Service + Controller (Day 28)
- DTOs with validation on every incoming request (this lesson)
- A global exception handler returning consistent error JSON (this lesson)
- MySQL as the backing database (Day 28)
// Example consistent error response shape returned for every failure
{
"errorCode": "NOT_FOUND",
"message": "Student with id 14 not found"
}
Push the finished project to GitHub with a clear README explaining the architecture — this becomes the project you walk an interviewer through on Day 30.
Interview tip: Interviewers consistently ask "why did you choose this approach?" about your own project decisions far more than they ask abstract theory questions — be ready to justify why you used a DTO instead of the entity, or why you centralized exception handling instead of try-catch in every controller method.