The Core Engine for Standardized API Responses and Exception Handling
api-payload-core provides the foundational interfaces and engine logic to manage consistent API response structures and centralized exception handling. It is designed to be framework-agnostic, allowing for flexible implementation across various environments.
BaseResponse: The root interface for all server responses. Implement this to define your standardized JSON envelope (e.g., status, message, result).BaseErrorCode: An interface that defines the data required for a response. It links specific error states to their corresponding HTTP status and messages.
ErrorCodeExceptionHandler: The core processor that intercepts exceptions, identifies the appropriateBaseErrorCode, and generates aBaseResponse. It also handles asynchronous execution of additional logic.ErrorCodeExceptionHandlerConfigurer: A fluent builder class to configure theErrorCodeExceptionHandlerwith custom error mappings and handlers.ServerApplicationException: A specialized runtime exception that carries aBaseErrorCode. Use this to throw business-specific errors within your service logic.
FailureResponseWriter: Responsible for converting aThrowableandBaseErrorCodeinto a finalBaseResponse.AdditionalExceptionHandler: An interface for side-effect logic (e.g., logging, Discord/Slack alerts) that runs asynchronously during the exception handling process.WebRequest&WebResponse: Abstractions for environment-specific request and response objects, allowing the engine to remain decoupled from specific technologies like Servlet or WebFlux.
You can set up the global exception handler using the Configurer.
@Configuration
public class ErrorHandlerConfig {
@Bean
public ErrorCodeExceptionHandler<DefaultBaseErrorCode> errorCodeExceptionHandler(
FailureResponseWriter<DefaultBaseErrorCode> failureResponseWriter,
List<AdditionalExceptionHandler<DefaultBaseErrorCode>> additionalHandlers
) {
return new ErrorCodeExceptionHandlerConfigurer<>(failureResponseWriter)
.addServerApplication(DefaultResponseErrorCode.BAD_REQUEST)
.addGlobalException(DefaultResponseErrorCode.INTERNAL_SERVER_ERROR)
.addAdvice(CustomException.class, CustomErrorCode.CUSTOM_ERROR_CODE)
.addAdditionalExceptionHandlers(additionalHandlers)
.build();
}
}Simply throw the ServerApplicationException with a predefined error code. The engine will catch it and map it to the correct response automatically.
@Service
public class ArticleService {
private final ArticleRepository articleRepository;
public Article findArticle(Long articleId) {
return articleRepository.findById(articleId)
.orElseThrow(() -> new ServerApplicationException(DefaultResponseErrorCode.NOT_FOUND));
}
}Create an asynchronous handler for tasks like logging, Discord notifications, or analytics by implementing AdditionalExceptionHandler.
@Component
public class LogAdditionalHandler implements AdditionalExceptionHandler<DefaultBaseErrorCode> {
@Override
public void doHandle(WebRequestWrapper req, WebResponseWrapper res, Throwable e, DefaultBaseErrorCode code) {
log.info("Error occurred at URI: {}, Method: {}",
req.getRequestURI(),
req.getMethod());
}
}You can define your own response format by implementing BaseResponse, BaseErrorCode, and FailureResponseWriter. This allows you to customize exactly how the JSON payload is structured for your specific business requirements.
- Define the Frame: Implement
BaseResponseto create your custom JSON structure (e.g., adding atimestamportransactionId). - Define the Data: Extend
BaseErrorCodeto include specific methods required for your custom response (e.g.,getInternalMessage()). - Implement the Writer: Implement
FailureResponseWriterusing your custom response and error code classes to define the final output logic. - Register: Register your custom writer as a Bean and use the
Configurerto link it to theErrorCodeExceptionHandler.
Tip
Advanced Setup: Use BaseResponse to define the architectural frame of the response and extend BaseErrorCode to provide the specific data needed by your custom writers. This separation of concerns ensures that your error logic remains clean and maintainable.
For most Spring Boot applications, it is highly recommended to use a dedicated Starter module (e.g., api-payload-webmvc-starter).
The Starter automatically handles the registration of these core components (Writers, Exception Handlers, etc.), allowing you to focus on your business logic with zero manual bean registration and minimal configuration.
© 2026 Project Namul - Beginner