From a960c00b3993749a2abc7cde82659dbcc2a54155 Mon Sep 17 00:00:00 2001 From: seheonnn Date: Thu, 9 May 2024 18:58:05 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20feat:=20Weather=20Service=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20=EC=A0=95=EA=B7=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/CustomException.java | 15 +++++ .../exception/GlobalExceptionHandler.java | 64 +++++++++++++++++++ .../exception/WeatherExceptionHandler.java | 9 +++ .../weatherservice/response/ApiResponse.java | 46 +++++++++++++ .../weatherservice/response/ErrorCode.java | 43 +++++++++++++ .../response/WeatherErrorCode.java | 24 +++++++ .../response/status/BaseErrorCode.java | 16 +++++ 7 files changed, 217 insertions(+) create mode 100644 weather-service/src/main/java/com/waither/weatherservice/exception/CustomException.java create mode 100644 weather-service/src/main/java/com/waither/weatherservice/exception/GlobalExceptionHandler.java create mode 100644 weather-service/src/main/java/com/waither/weatherservice/exception/WeatherExceptionHandler.java create mode 100644 weather-service/src/main/java/com/waither/weatherservice/response/ApiResponse.java create mode 100644 weather-service/src/main/java/com/waither/weatherservice/response/ErrorCode.java create mode 100644 weather-service/src/main/java/com/waither/weatherservice/response/WeatherErrorCode.java create mode 100644 weather-service/src/main/java/com/waither/weatherservice/response/status/BaseErrorCode.java diff --git a/weather-service/src/main/java/com/waither/weatherservice/exception/CustomException.java b/weather-service/src/main/java/com/waither/weatherservice/exception/CustomException.java new file mode 100644 index 00000000..842cfcd8 --- /dev/null +++ b/weather-service/src/main/java/com/waither/weatherservice/exception/CustomException.java @@ -0,0 +1,15 @@ +package com.waither.weatherservice.exception; + +import com.waither.weatherservice.response.status.BaseErrorCode; + +import lombok.Getter; + +@Getter +public class CustomException extends RuntimeException { + + private final BaseErrorCode errorCode; + + public CustomException(BaseErrorCode errorCode) { + this.errorCode = errorCode; + } +} diff --git a/weather-service/src/main/java/com/waither/weatherservice/exception/GlobalExceptionHandler.java b/weather-service/src/main/java/com/waither/weatherservice/exception/GlobalExceptionHandler.java new file mode 100644 index 00000000..789828da --- /dev/null +++ b/weather-service/src/main/java/com/waither/weatherservice/exception/GlobalExceptionHandler.java @@ -0,0 +1,64 @@ +package com.waither.weatherservice.exception; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import com.waither.weatherservice.response.ApiResponse; +import com.waither.weatherservice.response.ErrorCode; +import com.waither.weatherservice.response.status.BaseErrorCode; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + // @Valid 유효성 검사를 실패했을 시 + @ExceptionHandler(MethodArgumentNotValidException.class) + protected ResponseEntity>> handleMethodArgumentNotValidException( + MethodArgumentNotValidException ex + ) { + // 실패한 validation 을 담을 Map + Map failedValidations = new HashMap<>(); + List fieldErrors = ex.getBindingResult().getFieldErrors(); + // fieldErrors 를 순회하며 failedValidations 에 담는다. + fieldErrors.forEach(error -> failedValidations.put(error.getField(), error.getDefaultMessage())); + ApiResponse> errorResponse = ApiResponse.onFailure( + ErrorCode.VALIDATION_FAILED.getCode(), + ErrorCode.VALIDATION_FAILED.getMessage(), + failedValidations); + return ResponseEntity.status(ex.getStatusCode()).body(errorResponse); + } + + // Custom 예외에 대한 처리 + @ExceptionHandler({CustomException.class}) + public ResponseEntity> handleCustomException(CustomException e) { + log.warn("[WARNING] Custom Exception : {}", e.getErrorCode()); + BaseErrorCode errorCode = e.getErrorCode(); + return ResponseEntity. + status(errorCode.getHttpStatus()) + .body(errorCode.getErrorResponse()); + } + + @ExceptionHandler({Exception.class}) + public ResponseEntity> handleAllException(Exception e) { + log.error("[WARNING] Internal Server Error : {} ", e.getMessage()); + BaseErrorCode errorCode = ErrorCode.INTERNAL_SERVER_ERROR_500; + ApiResponse errorResponse = ApiResponse.onFailure( + errorCode.getCode(), + errorCode.getMessage(), + e.getMessage() + ); + return ResponseEntity + .status(errorCode.getHttpStatus()) + .body(errorResponse); + } + +} diff --git a/weather-service/src/main/java/com/waither/weatherservice/exception/WeatherExceptionHandler.java b/weather-service/src/main/java/com/waither/weatherservice/exception/WeatherExceptionHandler.java new file mode 100644 index 00000000..5f26b3ca --- /dev/null +++ b/weather-service/src/main/java/com/waither/weatherservice/exception/WeatherExceptionHandler.java @@ -0,0 +1,9 @@ +package com.waither.weatherservice.exception; + +import com.waither.weatherservice.response.status.BaseErrorCode; + +public class WeatherExceptionHandler extends CustomException { + public WeatherExceptionHandler(BaseErrorCode errorCode) { + super(errorCode); + } +} diff --git a/weather-service/src/main/java/com/waither/weatherservice/response/ApiResponse.java b/weather-service/src/main/java/com/waither/weatherservice/response/ApiResponse.java new file mode 100644 index 00000000..a98e1812 --- /dev/null +++ b/weather-service/src/main/java/com/waither/weatherservice/response/ApiResponse.java @@ -0,0 +1,46 @@ +package com.waither.weatherservice.response; + +import org.springframework.http.HttpStatus; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@JsonPropertyOrder({"code", "message", "result"}) +public class ApiResponse { + + // HTTP 상태 코드나 사용자 정의 코드 + private final String code; + // API 요청에 대한 설명이나 상태 메시지 + private final String message; + // result 값은 null이 아닐 때만 응답에 포함시킨다. + @JsonInclude(JsonInclude.Include.NON_NULL) + // 결과 데이터. (보통 dto -> json 파싱 될 예정) + private T result; + + // 성공한 경우 응답 생성 + public static ApiResponse onSuccess(T result) { + return new ApiResponse<>(String.valueOf(HttpStatus.OK.value()), HttpStatus.OK.getReasonPhrase(), result); + } + + // 성공한 경우 응답 생성 (상태 코드 지정 가능) + public static ApiResponse onSuccess(HttpStatus status, T result) { + return new ApiResponse<>(String.valueOf(status.value()), status.getReasonPhrase(), result); + } + + // 실패한 경우 응답 생성 + public static ApiResponse onFailure(String code, String message, T result) { + return new ApiResponse<>(code, message, result); + } + + // 실패한 경우 응답 생성 (데이터 없음) + public static ApiResponse onFailure(String statusCode, String message) { + return new ApiResponse<>(statusCode, message, null); + } + +} diff --git a/weather-service/src/main/java/com/waither/weatherservice/response/ErrorCode.java b/weather-service/src/main/java/com/waither/weatherservice/response/ErrorCode.java new file mode 100644 index 00000000..6be16245 --- /dev/null +++ b/weather-service/src/main/java/com/waither/weatherservice/response/ErrorCode.java @@ -0,0 +1,43 @@ +package com.waither.weatherservice.response; + +import org.springframework.http.HttpStatus; + +import com.waither.weatherservice.response.status.BaseErrorCode; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum ErrorCode implements BaseErrorCode { + + // 일반적인 ERROR 응답 + BAD_REQUEST_400(HttpStatus.BAD_REQUEST, + "COMMON400", + HttpStatus.BAD_REQUEST.getReasonPhrase()), + UNAUTHORIZED_401(HttpStatus.UNAUTHORIZED, + "COMMON401", + HttpStatus.UNAUTHORIZED.getReasonPhrase()), + FORBIDDEN_403(HttpStatus.FORBIDDEN, + "COMMON403", + HttpStatus.FORBIDDEN.getReasonPhrase()), + NOT_FOUND_404(HttpStatus.NOT_FOUND, + "COMMON404", + HttpStatus.NOT_FOUND.getReasonPhrase()), + INTERNAL_SERVER_ERROR_500( + HttpStatus.INTERNAL_SERVER_ERROR, + "COMMON500", + HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()), + + // 유효성 검사 + VALIDATION_FAILED(HttpStatus.BAD_REQUEST, "VALID400_0", "입력값에 대한 검증에 실패했습니다."); + + private final HttpStatus httpStatus; + private final String code; + private final String message; + + @Override + public ApiResponse getErrorResponse() { + return ApiResponse.onFailure(code, message); + } +} diff --git a/weather-service/src/main/java/com/waither/weatherservice/response/WeatherErrorCode.java b/weather-service/src/main/java/com/waither/weatherservice/response/WeatherErrorCode.java new file mode 100644 index 00000000..ba38a118 --- /dev/null +++ b/weather-service/src/main/java/com/waither/weatherservice/response/WeatherErrorCode.java @@ -0,0 +1,24 @@ +package com.waither.weatherservice.response; + +import org.springframework.http.HttpStatus; + +import com.waither.weatherservice.response.status.BaseErrorCode; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum WeatherErrorCode implements BaseErrorCode { + + WEATHER_ERROR_EXAMPLE(HttpStatus.BAD_REQUEST, "WEAT4000", "날씨 에러입니다."); + + private final HttpStatus httpStatus; + private final String code; + private final String message; + + @Override + public ApiResponse getErrorResponse() { + return ApiResponse.onFailure(code, message); + } +} diff --git a/weather-service/src/main/java/com/waither/weatherservice/response/status/BaseErrorCode.java b/weather-service/src/main/java/com/waither/weatherservice/response/status/BaseErrorCode.java new file mode 100644 index 00000000..a89beee3 --- /dev/null +++ b/weather-service/src/main/java/com/waither/weatherservice/response/status/BaseErrorCode.java @@ -0,0 +1,16 @@ +package com.waither.weatherservice.response.status; + +import org.springframework.http.HttpStatus; + +import com.waither.weatherservice.response.ApiResponse; + +public interface BaseErrorCode { + + HttpStatus getHttpStatus(); + + String getCode(); + + String getMessage(); + + ApiResponse getErrorResponse(); +} From 5459133823042c99435f68e86d972dcf823530fa Mon Sep 17 00:00:00 2001 From: seheonnn Date: Thu, 9 May 2024 19:21:37 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=ED=95=B8=EB=93=A4=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/WeatherController.java | 4 ++++ .../controller/WeatherTestController.java | 8 +++---- .../{ => request}/AccuweatherTestRequest.java | 2 +- .../dto/{ => request}/AirTestRequest.java | 2 +- .../{ => request}/ForeCastTestRequest.java | 2 +- .../dto/{ => request}/MsgTestRequest.java | 2 +- .../dto/request/WeatherRequest.java | 7 ++++++ .../dto/response/WeatherResponse.java | 7 ++++++ .../openapi/OpenApiException.java | 7 ------ .../weatherservice/openapi/OpenApiUtil.java | 23 ++++++++++++------- .../response/WeatherErrorCode.java | 3 ++- 11 files changed, 43 insertions(+), 24 deletions(-) create mode 100644 weather-service/src/main/java/com/waither/weatherservice/controller/WeatherController.java rename weather-service/src/main/java/com/waither/weatherservice/dto/{ => request}/AccuweatherTestRequest.java (62%) rename weather-service/src/main/java/com/waither/weatherservice/dto/{ => request}/AirTestRequest.java (53%) rename weather-service/src/main/java/com/waither/weatherservice/dto/{ => request}/ForeCastTestRequest.java (66%) rename weather-service/src/main/java/com/waither/weatherservice/dto/{ => request}/MsgTestRequest.java (52%) create mode 100644 weather-service/src/main/java/com/waither/weatherservice/dto/request/WeatherRequest.java create mode 100644 weather-service/src/main/java/com/waither/weatherservice/dto/response/WeatherResponse.java delete mode 100644 weather-service/src/main/java/com/waither/weatherservice/openapi/OpenApiException.java diff --git a/weather-service/src/main/java/com/waither/weatherservice/controller/WeatherController.java b/weather-service/src/main/java/com/waither/weatherservice/controller/WeatherController.java new file mode 100644 index 00000000..0f6a0fe0 --- /dev/null +++ b/weather-service/src/main/java/com/waither/weatherservice/controller/WeatherController.java @@ -0,0 +1,4 @@ +package com.waither.weatherservice.controller; + +public class WeatherController { +} diff --git a/weather-service/src/main/java/com/waither/weatherservice/controller/WeatherTestController.java b/weather-service/src/main/java/com/waither/weatherservice/controller/WeatherTestController.java index 6ba2d24c..0f808b5d 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/controller/WeatherTestController.java +++ b/weather-service/src/main/java/com/waither/weatherservice/controller/WeatherTestController.java @@ -9,10 +9,10 @@ import org.springframework.web.bind.annotation.RestController; import com.fasterxml.jackson.core.JsonProcessingException; -import com.waither.weatherservice.dto.AccuweatherTestRequest; -import com.waither.weatherservice.dto.AirTestRequest; -import com.waither.weatherservice.dto.ForeCastTestRequest; -import com.waither.weatherservice.dto.MsgTestRequest; +import com.waither.weatherservice.dto.request.AccuweatherTestRequest; +import com.waither.weatherservice.dto.request.AirTestRequest; +import com.waither.weatherservice.dto.request.ForeCastTestRequest; +import com.waither.weatherservice.dto.request.MsgTestRequest; import com.waither.weatherservice.service.WeatherService; import lombok.RequiredArgsConstructor; diff --git a/weather-service/src/main/java/com/waither/weatherservice/dto/AccuweatherTestRequest.java b/weather-service/src/main/java/com/waither/weatherservice/dto/request/AccuweatherTestRequest.java similarity index 62% rename from weather-service/src/main/java/com/waither/weatherservice/dto/AccuweatherTestRequest.java rename to weather-service/src/main/java/com/waither/weatherservice/dto/request/AccuweatherTestRequest.java index b61db344..79d68329 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/dto/AccuweatherTestRequest.java +++ b/weather-service/src/main/java/com/waither/weatherservice/dto/request/AccuweatherTestRequest.java @@ -1,4 +1,4 @@ -package com.waither.weatherservice.dto; +package com.waither.weatherservice.dto.request; public record AccuweatherTestRequest( double latitude, diff --git a/weather-service/src/main/java/com/waither/weatherservice/dto/AirTestRequest.java b/weather-service/src/main/java/com/waither/weatherservice/dto/request/AirTestRequest.java similarity index 53% rename from weather-service/src/main/java/com/waither/weatherservice/dto/AirTestRequest.java rename to weather-service/src/main/java/com/waither/weatherservice/dto/request/AirTestRequest.java index 8373b2e2..0d6b5db3 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/dto/AirTestRequest.java +++ b/weather-service/src/main/java/com/waither/weatherservice/dto/request/AirTestRequest.java @@ -1,4 +1,4 @@ -package com.waither.weatherservice.dto; +package com.waither.weatherservice.dto.request; public record AirTestRequest( String searchDate diff --git a/weather-service/src/main/java/com/waither/weatherservice/dto/ForeCastTestRequest.java b/weather-service/src/main/java/com/waither/weatherservice/dto/request/ForeCastTestRequest.java similarity index 66% rename from weather-service/src/main/java/com/waither/weatherservice/dto/ForeCastTestRequest.java rename to weather-service/src/main/java/com/waither/weatherservice/dto/request/ForeCastTestRequest.java index 44acf314..be2dbc30 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/dto/ForeCastTestRequest.java +++ b/weather-service/src/main/java/com/waither/weatherservice/dto/request/ForeCastTestRequest.java @@ -1,4 +1,4 @@ -package com.waither.weatherservice.dto; +package com.waither.weatherservice.dto.request; public record ForeCastTestRequest( int nx, diff --git a/weather-service/src/main/java/com/waither/weatherservice/dto/MsgTestRequest.java b/weather-service/src/main/java/com/waither/weatherservice/dto/request/MsgTestRequest.java similarity index 52% rename from weather-service/src/main/java/com/waither/weatherservice/dto/MsgTestRequest.java rename to weather-service/src/main/java/com/waither/weatherservice/dto/request/MsgTestRequest.java index 4f113864..60ebdf39 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/dto/MsgTestRequest.java +++ b/weather-service/src/main/java/com/waither/weatherservice/dto/request/MsgTestRequest.java @@ -1,4 +1,4 @@ -package com.waither.weatherservice.dto; +package com.waither.weatherservice.dto.request; public record MsgTestRequest( String location diff --git a/weather-service/src/main/java/com/waither/weatherservice/dto/request/WeatherRequest.java b/weather-service/src/main/java/com/waither/weatherservice/dto/request/WeatherRequest.java new file mode 100644 index 00000000..d43122dc --- /dev/null +++ b/weather-service/src/main/java/com/waither/weatherservice/dto/request/WeatherRequest.java @@ -0,0 +1,7 @@ +package com.waither.weatherservice.dto.request; + +import lombok.Builder; + +@Builder +public record WeatherRequest() { +} diff --git a/weather-service/src/main/java/com/waither/weatherservice/dto/response/WeatherResponse.java b/weather-service/src/main/java/com/waither/weatherservice/dto/response/WeatherResponse.java new file mode 100644 index 00000000..f6d3198b --- /dev/null +++ b/weather-service/src/main/java/com/waither/weatherservice/dto/response/WeatherResponse.java @@ -0,0 +1,7 @@ +package com.waither.weatherservice.dto.response; + +import lombok.Builder; + +@Builder +public record WeatherResponse() { +} diff --git a/weather-service/src/main/java/com/waither/weatherservice/openapi/OpenApiException.java b/weather-service/src/main/java/com/waither/weatherservice/openapi/OpenApiException.java deleted file mode 100644 index 6a6b8df2..00000000 --- a/weather-service/src/main/java/com/waither/weatherservice/openapi/OpenApiException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.waither.weatherservice.openapi; - -public class OpenApiException extends RuntimeException { - public OpenApiException(String message) { - super(message); - } -} diff --git a/weather-service/src/main/java/com/waither/weatherservice/openapi/OpenApiUtil.java b/weather-service/src/main/java/com/waither/weatherservice/openapi/OpenApiUtil.java index bf756fd8..991c7ed9 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/openapi/OpenApiUtil.java +++ b/weather-service/src/main/java/com/waither/weatherservice/openapi/OpenApiUtil.java @@ -17,6 +17,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.waither.weatherservice.exception.WeatherExceptionHandler; +import com.waither.weatherservice.response.WeatherErrorCode; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -69,14 +71,14 @@ public List callForeCastApi( .accept(MediaType.APPLICATION_JSON) .retrieve().bodyToMono(ForeCastOpenApiResponse.class) .onErrorResume(throwable -> { - throw new OpenApiException(RESPONSE_EXCEPTION_MSG); + throw new WeatherExceptionHandler(WeatherErrorCode.WEATHER_OPENAPI_ERROR); }) .block().getResponse(); if (response.getHeader().getResultCode().equals("00")) { return response.getBody().getItems().getItem(); } else { - throw new OpenApiException(response.getHeader().getResultMsg()); + throw new WeatherExceptionHandler(WeatherErrorCode.WEATHER_OPENAPI_ERROR); } } @@ -124,7 +126,7 @@ public List callDisasterMsgApi(String location) thro }) .retrieve().bodyToMono(String.class) .onErrorResume(throwable -> { - throw new OpenApiException(RESPONSE_EXCEPTION_MSG); + throw new WeatherExceptionHandler(WeatherErrorCode.WEATHER_OPENAPI_ERROR); }) .block(); @@ -135,7 +137,8 @@ public List callDisasterMsgApi(String location) thro return response.getDisasterMsg().get(1).getRow(); } else { String resultMsg = response.getDisasterMsg().get(0).getHead().get(2).getResultData().getResultMsg(); - throw new OpenApiException(resultMsg); + log.info("[*] OpenApi Error : {}", resultMsg); + throw new WeatherExceptionHandler(WeatherErrorCode.WEATHER_OPENAPI_ERROR); } } @@ -161,8 +164,11 @@ public List callAirKorea(String searchDate) throw AirKoreaOpenApiResponse.Response response = webClient.get() .uri(uri) .accept(MediaType.APPLICATION_JSON) - .retrieve().bodyToMono(AirKoreaOpenApiResponse.class) - .blockOptional().orElseThrow(() -> new OpenApiException(RESPONSE_EXCEPTION_MSG)).getResponse(); + .retrieve() + .bodyToMono(AirKoreaOpenApiResponse.class) + .blockOptional() + .orElseThrow(() -> new WeatherExceptionHandler(WeatherErrorCode.WEATHER_OPENAPI_ERROR)) + .getResponse(); if (response.getHeader().getResultCode().equals("00")) { @@ -178,7 +184,8 @@ public List callAirKorea(String searchDate) throw return items; } else { - throw new OpenApiException(response.getHeader().getResultMsg()); + log.info("[*] OpenApi Error : {}", response.getHeader().getResultMsg()); + throw new WeatherExceptionHandler(WeatherErrorCode.WEATHER_OPENAPI_ERROR); } } @@ -215,7 +222,7 @@ public String callAccuweatherLocationApi(double latitude, double longitude) thro .accept(MediaType.APPLICATION_JSON) .retrieve().bodyToMono(String.class) .onErrorResume(throwable -> { - throw new OpenApiException(RESPONSE_EXCEPTION_MSG); + throw new WeatherExceptionHandler(WeatherErrorCode.WEATHER_OPENAPI_ERROR); }) .block(); diff --git a/weather-service/src/main/java/com/waither/weatherservice/response/WeatherErrorCode.java b/weather-service/src/main/java/com/waither/weatherservice/response/WeatherErrorCode.java index ba38a118..1c542b3e 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/response/WeatherErrorCode.java +++ b/weather-service/src/main/java/com/waither/weatherservice/response/WeatherErrorCode.java @@ -11,7 +11,8 @@ @AllArgsConstructor public enum WeatherErrorCode implements BaseErrorCode { - WEATHER_ERROR_EXAMPLE(HttpStatus.BAD_REQUEST, "WEAT4000", "날씨 에러입니다."); + WEATHER_EXAMPLE_ERROR(HttpStatus.BAD_REQUEST, "WEAT4000", "날씨 에러입니다."), + WEATHER_OPENAPI_ERROR(HttpStatus.BAD_REQUEST, "WEAT4001", "OpenApi 관련 오류입니다."); private final HttpStatus httpStatus; private final String code;