The Ecommerce API uses Spring’s @RestControllerAdvice to provide consistent error responses across all endpoints. This guide explains the error handling mechanism and response formats.
Exception Architecture
The API uses custom exception classes with corresponding advice handlers to return meaningful error messages.
Exception Classes
Each domain has its ownNotFoundException:
ProductNotFoundException.java
UserNotFoundException.java
CategoryNotFoundException.java
package com.example.ecommerce.product;
public class ProductNotFoundException extends RuntimeException {
public ProductNotFoundException ( Long id ) {
super ( "There is no Product with product id: " + id);
}
}
Exception Handlers
Exception handlers use @RestControllerAdvice to catch exceptions and return formatted responses:
ProductNotFoundAdvice.java
UserNotFoundAdvice.java
package com.example.ecommerce.product;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@ RestControllerAdvice
public class ProductNotFoundAdvice {
@ ExceptionHandler ( ProductNotFoundException . class )
@ ResponseStatus ( HttpStatus . NOT_FOUND )
String HandleProductNotFoundException ( ProductNotFoundException ex ) {
return ex . getMessage ();
}
}
HTTP Status Codes
The API uses standard HTTP status codes to indicate the type of error:
Status Code Description When It Occurs 200 OKRequest succeeded Successful GET, PUT, PATCH 201 CreatedResource created Successful POST 204 No ContentSuccessful deletion Successful DELETE 400 Bad RequestInvalid request data Missing required fields, validation errors 404 Not FoundResource not found Invalid ID in path parameter 500 Internal Server ErrorServer error Unexpected server-side errors
Error responses return plain text messages with appropriate HTTP status codes.
404 Not Found Errors
Product Not Found
Response
curl http://localhost:8080/products/999
curl http://localhost:8080/users/999
Category Not Found
Response
curl http://localhost:8080/categories/999
400 Bad Request Errors
Bad request errors occur when required data is missing or invalid:
curl -X POST http://localhost:8080/users \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected] ",
"name": "John Doe"
}'
curl -X POST http://localhost:8080/users \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected] ",
"name": "Jane Doe",
"password": "password123"
}'
Common Error Scenarios
Resource Not Found
Occurs when requesting a resource with an invalid ID: @ GetMapping ( "/products/{id}" )
EntityModel < ProductView > findOne (@ PathVariable Long id){
Product product = productRepository . findById (id)
. orElseThrow (() -> new ProductNotFoundException (id));
return productAssembler . toModel (product);
}
Response: HTTP/1.1 404 Not Found
There is no Product with product id: 123
Validation Errors
Occurs when required fields are missing or invalid: @ PostMapping ( "/users" )
ResponseEntity < EntityModel < UserView >> save (@ RequestBody User newUser) {
if ( newUser . getPassword () == null || newUser . getPassword (). trim (). isEmpty ()) {
return ResponseEntity . badRequest (). build ();
}
// ...
}
Response:
Duplicate Resource
Occurs when attempting to create a resource that already exists: if ( userRepository . existsByEmail ( newUser . getEmail ())) {
return ResponseEntity . badRequest (). build ();
}
Response:
Error Handling Best Practices
Client-Side Error Handling
Always check the HTTP status code and handle errors appropriately:
async function getProduct ( id ) {
try {
const response = await fetch ( `http://localhost:8080/products/ ${ id } ` );
if ( ! response . ok ) {
if ( response . status === 404 ) {
const errorMessage = await response . text ();
console . error ( 'Product not found:' , errorMessage );
return null ;
}
throw new Error ( `HTTP error! status: ${ response . status } ` );
}
return await response . json ();
} catch ( error ) {
console . error ( 'Error fetching product:' , error );
throw error ;
}
}
Handling Different Error Types
async function createUser ( userData ) {
try {
const response = await fetch ( 'http://localhost:8080/users' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ( userData ),
});
if ( response . status === 400 ) {
console . error ( 'Invalid user data or duplicate email' );
return { error: 'Validation failed' };
}
if ( response . status === 201 ) {
return await response . json ();
}
throw new Error ( `Unexpected status: ${ response . status } ` );
} catch ( error ) {
console . error ( 'Error creating user:' , error );
throw error ;
}
}
Custom Exception Handling
You can extend the error handling by creating additional exception handlers:
CustomExceptionHandler.java
@ RestControllerAdvice
public class CustomExceptionHandler {
@ ExceptionHandler ( MethodArgumentNotValidException . class )
@ ResponseStatus ( HttpStatus . BAD_REQUEST )
public Map < String , String > handleValidationExceptions (
MethodArgumentNotValidException ex ) {
Map < String , String > errors = new HashMap <>();
ex . getBindingResult (). getAllErrors (). forEach ((error) -> {
String fieldName = ((FieldError) error). getField ();
String errorMessage = error . getDefaultMessage ();
errors . put (fieldName, errorMessage);
});
return errors;
}
@ ExceptionHandler ( Exception . class )
@ ResponseStatus ( HttpStatus . INTERNAL_SERVER_ERROR )
public String handleGenericException ( Exception ex ) {
return "An unexpected error occurred: " + ex . getMessage ();
}
}
In production, avoid exposing detailed error messages that could reveal sensitive information about your system architecture.
Testing Error Scenarios
Use these curl commands to test different error scenarios:
Test 404 - Product Not Found
Test 404 - User Not Found
Test 400 - Missing Password
Test 400 - Empty Password
Test 204 - Successful Delete
curl -i http://localhost:8080/products/999999
The -i flag in curl includes HTTP headers in the output, making it easy to see the status code.
Error Response Examples
Complete Error Flow
Client Request
Client attempts to fetch a non-existent product: curl -i http://localhost:8080/products/999
Exception Thrown
Controller throws ProductNotFoundException: Product product = productRepository . findById ( 999L )
. orElseThrow (() -> new ProductNotFoundException ( 999L ));
Exception Caught
ProductNotFoundAdvice catches the exception: @ ExceptionHandler ( ProductNotFoundException . class )
@ ResponseStatus ( HttpStatus . NOT_FOUND )
String HandleProductNotFoundException ( ProductNotFoundException ex) {
return ex . getMessage ();
}
Response Sent
Client receives formatted error response: HTTP/1.1 404 Not Found
Content-Type: text/plain
Content-Length: 44
There is no Product with product id: 999
Debugging Tips
Use the -i or -v flag with curl to see full HTTP headers
Check application logs for stack traces during development
Enable Spring Boot debug logging: logging.level.org.springframework=DEBUG
Use browser DevTools Network tab to inspect API responses
Test error scenarios in addition to success cases
Next Steps
API Reference View detailed endpoint documentation and response codes
Setup Guide Learn how to configure error logging and monitoring