Skip to main content
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:
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:
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 CodeDescriptionWhen It Occurs
200 OKRequest succeededSuccessful GET, PUT, PATCH
201 CreatedResource createdSuccessful POST
204 No ContentSuccessful deletionSuccessful DELETE
400 Bad RequestInvalid request dataMissing required fields, validation errors
404 Not FoundResource not foundInvalid ID in path parameter
500 Internal Server ErrorServer errorUnexpected server-side errors

Error Response Format

Error responses return plain text messages with appropriate HTTP status codes.

404 Not Found Errors

curl http://localhost:8080/products/999
curl http://localhost:8080/users/999
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

1

Resource Not Found

Occurs when requesting a resource with an invalid ID:
ProductController.java
@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
2

Validation Errors

Occurs when required fields are missing or invalid:
UserController.java
@PostMapping("/users")
ResponseEntity<EntityModel<UserView>> save(@RequestBody User newUser) {
    if (newUser.getPassword() == null || newUser.getPassword().trim().isEmpty()) {
        return ResponseEntity.badRequest().build();
    }
    // ...
}
Response:
HTTP/1.1 400 Bad Request
3

Duplicate Resource

Occurs when attempting to create a resource that already exists:
UserController.java
if (userRepository.existsByEmail(newUser.getEmail())) {
    return ResponseEntity.badRequest().build();
}
Response:
HTTP/1.1 400 Bad Request

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:
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

1

Client Request

Client attempts to fetch a non-existent product:
curl -i http://localhost:8080/products/999
2

Exception Thrown

Controller throws ProductNotFoundException:
Product product = productRepository.findById(999L)
    .orElseThrow(() -> new ProductNotFoundException(999L));
3

Exception Caught

ProductNotFoundAdvice catches the exception:
@ExceptionHandler(ProductNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
String HandleProductNotFoundException(ProductNotFoundException ex) {
    return ex.getMessage();
}
4

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

Build docs developers (and LLMs) love