diff --git a/README.md b/README.md index 3bd896e..3ff788d 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,6 @@ Dependency Development Repository for Spring Beginners ![Java version](https://img.shields.io/badge/Java%20version-17-orange) ## Package -- ### [Api-Payload](https://github.com/projectnamul/beginner/tree/develop/api-payload) - Dependency for Unified response and error handler settings that will use at initial project settings +- ### [api-payload-core](https://github.com/projectnamul/beginner/tree/develop/api-payload-core) + This module offer Error Handling module to make unified response about several exceptions. diff --git a/api-payload-core/README.md b/api-payload-core/README.md index 47819cc..eda8aac 100644 --- a/api-payload-core/README.md +++ b/api-payload-core/README.md @@ -1,25 +1,74 @@ -# Api Payload -The module to unify response you can use DefaultResponse or your custom response +# api-payload-core +You can make and use class to make response about several exceptions. -## Default -### How to add ExceptionAdvice with DefaultResponse +--- + +## Content of Table +[1. Classes & Interfaces](#classes-and-interfaces) + +[2. How to use](#how-to-use) + +[2 - 1. Default](#default) + +[2 - 2 Custom](#custom) + +---- + +## Classes and Interfaces +Descriptions of classes and Interfaces + +### BaseResponse +- This interface is just response type which you want to send to client. You can make type of server response with implementing this interface. Make a response class and declare variable you want to contain in response. + +### BaseErrorCode +- This interface returns data that needs a response. After creating a response type with the BaseResponse interface, extend the BaseErrorCode interface to create an interface that can return the data that needs a response that you created. Then, implement other interfaces with the interface you implemented with BaseErrorCode. + +### FailureResponseWriter +- This interface responds with throwable (Exception) and BaseErrorCode. Implement to return BaseResponse using BaseErrorCode's method and Throwable. + +### AdditionalExceptionHandler +- This interface performs additional logic except for generating response by implementing this interfaace. Like logging, send discord or alarm... etc. +> If you add it to ErrorCodeExceptionHandler with ErrorCodeExceptionHandlerConfigurer, you must control consistency problem. Because it runs asynchronously in ErrorCodeExceptionHandler's handle method. + +### WebRequest & WebResponse +- This interface offer some method can use in AdditionalExceptionHandler. You can implement it yourself or use a class already implemented from another module. + +### ErrorCodeExceptionHandler +- Based on the transmitted exception, this class finds the appropriate BaseErrorCode, generates responses, and asynchronously executes additional logic. It also provides a way to find the right BaseErrorCode for Throwable. + +### ErrorCodeExceptionHandlerConfigurer +- This class make ErrorCodeExceptionHandler with several methods. Developer can set ErrorCodeExceptionHandler with this class by using classes that developer created. + +### ServerApplicationException +- This class is just exception class that contain BaseErrorCode. Developer can make another exception class by extending it. Also, It can get cause(Throwable) for stacktrace + +--- + +## How to use +### Default Just add one config file. Because `DefaultResponseWriter` is already registered in Bean, If you have not registered class which implement that `FailureResponseWriter` interfaces to bean ```java @Configuration -public class ExceptionAdviceConfig { +public class ErrorHandlerConfig { @Bean - ExceptionAdvice defaultExceptionAdviceConfigurer( + public ErrorCodeExceptionHandler errorCodeExceptionHandler( FailureResponseWriter failureResponseWriter, - List> additionalExceptionHandlers + List> additionalExceptionHandlerList ) { - return new DefaultExceptionAdviceConfigurer(failureResponseWriter) - .addAdditionalExceptionHandlers(additionalExceptionHandlers) + ErrorCodeExceptionHandlerConfigurer configurer = new ErrorCodeExceptionHandlerConfigurer<>(failureResponseWriter); + return configurer + .addServerApplication(DefaultResponseErrorCode.BAD_REQUEST) + .addGlobalException(DefaultResponseErrorCode.INTERNAL_SERVER_ERROR) + .addAdvice(CustomException.class, CustomErrorCode.CUSTOM_ERROR_CODE) + // ... + .addAdditionalExceptionHandlers(additionalExceptionHandlerList) .build(); } + } ``` @@ -38,17 +87,39 @@ public class TestController { } ``` +or +```java + @GetMapping("/success") + public BaseResponse success() { + return successResponseWriter.onSuccess(DefaultResponseSuccessCode.OK, "Success"); + } +``` + +> ⚠️ Setting the return value to BaseResponse may prevent the Swagger's response format from appearing properly. + ### How to add AdditionalExceptionHandler You can add additional logic with implementing AdditionalExceptionHandler and add it to bean. ```java -@Slf4j -@Component -public class ExceptionAdviceLoggingHandler implements AdditionalExceptionHandler { +public class LogAdditionalHandler implements AdditionalExceptionHandler { @Override - public void doHandle(HttpServletRequest request, HttpServletResponse response, Exception e, DefaultBaseErrorCode code) { - log.warn("Error occur: class: {}, message: {}", e.getClass(), code.getMessage()); + public void doHandle(WebRequestWrapper webRequestWrapper, WebResponseWrapper webResponseWrapper, Throwable e, DefaultBaseErrorCode defaultBaseErrorCode) { + log.info(""" + Cookie: {}, + URI: {}, + Header: {}, + Method: {}, + Address: {}, + UserAgent: {}, + """, + webRequestWrapper.getCookie("JSESSIONID"), + webRequestWrapper.getRequestURI(), + webRequestWrapper.getHeader("content-type"), + webRequestWrapper.getMethod(), + webRequestWrapper.getRemoteAddress().get(), + webRequestWrapper.getUserAgent().get()); + } } ``` @@ -85,15 +156,17 @@ public class ArticleService { } ``` +--- + ## Custom ### How to make your custom response You can make custom response by implementing BaseResponse, BaseErrorCode and FailureResponseWriter. -1. Make custom BaseResponse -2. Make custom BaseErrorCode -3. Make custom FailureResponseWriter -4. Register your custom Writer in bean and implement custom BaseErrorCode +1. Make custom response class with BaseResponse +2. Make custom interface with BaseErrorCode. It has several method which you need to create response +3. Make custom FailureResponseWriter with BaseResponse, BaseErrorCode which you implemented. +4. Register your custom Writer in bean and create ErrorCodeExceptionHandler with Configurer. > Use BaseResponse to make frame of the response and expand the BaseErrorCode to define the data needed to generate the response as a method. Using the expanded BaseErrorCode, Implement the FailureResponseWriter which creates the response. Then, If you implement the Custom BaseErrorCode class and pass it to ServerApplicationException, the ExceptionAdvice can make Response and return it. @@ -138,7 +211,7 @@ You implement `CustomResponseFailureWriter` to make CustomResponse with CustomBa public class CustomFailureResponseWriter implements FailureResponseWriter { @Override - public BaseResponse onFailure(Exception e, CustomBaseErrorCode code) { + public BaseResponse onFailure(Throwable e, CustomBaseErrorCode code) { return new CustomResponse<>(code.getHttpStatus(), code.getMessage(), null); } } @@ -165,21 +238,23 @@ public enum CustomErrorCode implements CustomBaseErrorCode { } ``` - #### Config ```java - @Configuration public class ExceptionAdviceConfig { @Bean - ExceptionAdvice defaultExceptionAdviceConfigurer( + ErrorCodeExceptionHandler customErrorCodeExceptionHandler( FailureResponseWriter failureResponseWriter, List> additionalExceptionHandlers ) { - return new ExceptionAdviceConfigurer<>(failureResponseWriter) - .withDefault(CustomErrorCode.ERROR, CustomErrorCode.BAD_ERROR) - .addAdditionalExceptionHandlers(additionalExceptionHandlers) + ErrorCodeExceptionHandlerConfigurer configurer = new ErrorCodeExceptionHandlerConfigurer<>(failureResponseWriter); + return configurer + .addServerApplication(CustomErrorCode.ERROR) + .addGlobalException(CustomErrorCode.BAD_ERROR) + .addAdvice(CustomNotFoundException.class, CustomErrorCode.NOT_FOUND) + // ... + .addAdditionalExceptionHandlers(additionalExceptionHandlerList) .build(); } } @@ -196,7 +271,7 @@ public class ArticleService { @Transactional(readonly = true) public Article findArticle(Long articleId){ - return articleRepository.findById(articleId).orElseThrow(() -> new ServerApplicationException(CustomErrorCode.NOT_FOUND)); + return articleRepository.findById(articleId).orElseThrow(() -> new CustomException(CustomErrorCode.NOT_FOUND)); } } ``` diff --git a/api-payload-webmvc/README.md b/api-payload-webmvc/README.md new file mode 100644 index 0000000..797e6b7 --- /dev/null +++ b/api-payload-webmvc/README.md @@ -0,0 +1,18 @@ +# api-payload-webmvc + +It is a dependency that helps users easily use functions in a Spring MVC environment by using it as 'api-payload-core'. + + +## Classes + +### HttpServletWebRequestWrapper +- A class that implements WebRequestWrapper's method using HttpServletRequest. It makes it easy to change and use HttpServletRequestWrapper to WebRequestWrapper through a constructor or static method. + +### HttpServletWebResponseWrapper +- A class that implements WebResponseWrapper's method using HttpServletResponse. It makes it easy to change and use HttpServletResponse to WebResponseWrapper through a constructor or static method. + +### HttpServletErrorCodeExceptionHandlerConfigurer +- This class implements the ErrorCodeExceptionHandlerConfigurer, which supports methods that make it easy to add errors that usually occur in the Dispatcher Servlet environment. + +### ExceptionRestControllerAdvice +- RestControllerAdvice is a class implemented using ErrorCodeExceptionHandler that helps developers add it through Bean rather than directly. If it needs to be modified, you can override it. Of course, you can implement it yourself without using it. \ No newline at end of file