Exception Handling
📝 Note: This guide uses generic placeholder names to be reusable across any Spring Boot microservice. Replace with your actual implementation:
{YourService}→ Your service name (e.g.,OrderService,PaymentService)BusinessService→ Your core service (e.g.,OrderService,UserService)DataService→ Your data processing service (e.g.,PaymentService,InventoryService)IntegrationService→ Your external integration (e.g.,PaymentGatewayService){RequestType}→ Your request DTO (e.g.,CreateOrderRequest){ResponseType}→ Your response DTO (e.g.,OrderResponse)
Quick Reference
Package Location
exception/
├── RequestUnauthorizedExceptionWithSubcode.java # 401 with subcode
└── handler/
├── AlreadyExistsWithSubcodeException.java # 409 with subcode
└── AppExceptionHandler.java # Global exception handler
Example Package
com.example.microserviceorch.exception.example
Key Patterns
1. Custom Exception with Subcode
throw new RequestUnauthorizedExceptionWithSubcode(
"Account does not have a password",
"no_password"
);
2. Fluent Builder Pattern
throw new AlreadyExistsWithSubcodeException("Account already exists")
.withSubcode("no_password");
3. Global Exception Handler
@ControllerAdvice
@ResponseBody
public class AppExceptionHandler extends ApiExceptionHandler {
@ExceptionHandler({RequestUnauthorizedException.class})
public ResponseEntity<GeneralError> requestUnauthorizedException(
RequestUnauthorizedException e) {
LOG.warn("{}{}, 401", e.getClass().getCanonicalName(), e.getMessage());
return this.createGeneralError("Unauthorized request", HttpStatus.UNAUTHORIZED);
}
}
4. Exception Translation
try {
accountApiClient.postPasswordlessAccount(email);
} catch (HttpProxyCallException e) {
if (e.getHttpStatusCode() == 409) {
throw translateConflictException(e);
}
}
HTTP Status Mapping
| Exception | Status | Response |
|---|---|---|
BadRequestException |
400 | GeneralError |
RequestUnauthorizedException |
401 | GeneralError |
RequestUnauthorizedExceptionWithSubcode |
401 | SchemasErrorWithSubcode |
AlreadyExistsWithSubcodeException |
409 | SchemasErrorWithSubcode |
InternalServerException |
500 | GeneralError |
Error Response Schemas
GeneralError
{
"success": false,
"status": 400,
"error": "Invalid input parameter"
}
SchemasErrorWithSubcode
{
"success": false,
"status": 401,
"error": "Account does not have a password set",
"subcode": "no_password"
}
Detailed Documentation
- Architecture: guides/architecture.md
- Best Practices: guides/best-practices.md
- Testing: guides/testing.md
- Examples: examples/README.md
Code Formatting
./gradlew spotlessApply