Feat: Swagger 커스텀 설정 추가
This commit is contained in:
parent
6b9a68589e
commit
d928af889e
@ -43,6 +43,9 @@ dependencies {
|
|||||||
|
|
||||||
// GJson
|
// GJson
|
||||||
implementation 'com.google.code.gson:gson:2.7'
|
implementation 'com.google.code.gson:gson:2.7'
|
||||||
|
|
||||||
|
//Swagger
|
||||||
|
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.named('test') {
|
tasks.named('test') {
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
package com.worlabel.global.config;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
|
||||||
|
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
|
||||||
|
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
|
||||||
|
import io.swagger.v3.oas.annotations.info.Info;
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecurityScheme;
|
||||||
|
import org.springdoc.core.customizers.OperationCustomizer;
|
||||||
|
import org.springdoc.core.models.GroupedOpenApi;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@OpenAPIDefinition(
|
||||||
|
info = @Info(
|
||||||
|
title = "auto labeling API",
|
||||||
|
description = "auto labeling API 목록입니다.",
|
||||||
|
version = "v1.0"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@SecurityScheme(
|
||||||
|
name = "Authorization",
|
||||||
|
type = SecuritySchemeType.HTTP,
|
||||||
|
bearerFormat = "JWT",
|
||||||
|
in = SecuritySchemeIn.HEADER,
|
||||||
|
scheme = "Bearer",
|
||||||
|
description = "access token"
|
||||||
|
)
|
||||||
|
public class SwaggerConfig {
|
||||||
|
|
||||||
|
private final String[] noRequiredTokenApi = {"/register", "/login", "/reissue","/login/oauth", "/oauth2/**",
|
||||||
|
"/login/oauth2/**", "/error", "login/oauth2/code/kakao", "/register/duplicate", "/test"};
|
||||||
|
|
||||||
|
private final OperationCustomizer operationCustomizer;
|
||||||
|
|
||||||
|
public SwaggerConfig(OperationCustomizer operationCustomizer) {
|
||||||
|
this.operationCustomizer = operationCustomizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public GroupedOpenApi nonSecurityGroup(){ //jwt 토큰 불필요한 api
|
||||||
|
return GroupedOpenApi.builder()
|
||||||
|
.group("token 불필요 API")
|
||||||
|
.pathsToMatch(noRequiredTokenApi)
|
||||||
|
.addOperationCustomizer(operationCustomizer)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public GroupedOpenApi securityGroup(){ //jwt 토큰 필요한 api
|
||||||
|
return GroupedOpenApi.builder()
|
||||||
|
.group("token 필요 API")
|
||||||
|
.pathsToExclude(noRequiredTokenApi)
|
||||||
|
.addOperationCustomizer(operationCustomizer)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
|||||||
|
package com.worlabel.global.config.swagger;
|
||||||
|
|
||||||
|
import com.worlabel.global.exception.CustomException;
|
||||||
|
import com.worlabel.global.response.BaseResponse;
|
||||||
|
import com.worlabel.global.response.CustomError;
|
||||||
|
import com.worlabel.global.response.ErrorResponse;
|
||||||
|
import io.swagger.v3.oas.models.Operation;
|
||||||
|
import io.swagger.v3.oas.models.examples.Example;
|
||||||
|
import io.swagger.v3.oas.models.media.Content;
|
||||||
|
import io.swagger.v3.oas.models.media.MediaType;
|
||||||
|
import io.swagger.v3.oas.models.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.models.responses.ApiResponses;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
|
import org.springdoc.core.customizers.OperationCustomizer;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.method.HandlerMethod;
|
||||||
|
|
||||||
|
import com.worlabel.global.exception.ErrorCode;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class CustomOperationCustomizer implements OperationCustomizer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Operation customize(Operation operation, HandlerMethod handlerMethod) {
|
||||||
|
SwaggerApiError swaggerApiError = handlerMethod.getMethodAnnotation(SwaggerApiError.class);
|
||||||
|
operation.getResponses().remove("500");
|
||||||
|
if (swaggerApiError != null) {
|
||||||
|
generateErrorCodeResponse(operation, swaggerApiError.value());
|
||||||
|
}
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
//에러 코드로 error response 만들어 ApiResponse 에 넣음
|
||||||
|
private void generateErrorCodeResponse(Operation operation, ErrorCode[] errorCodes) {
|
||||||
|
ApiResponses responses = operation.getResponses();
|
||||||
|
|
||||||
|
Map<Integer, List<BaseResponse<CustomError>>> statusWithErrorResponse = Arrays.stream(errorCodes)
|
||||||
|
.map(errorCode -> ErrorResponse.of(new CustomException(errorCode)))
|
||||||
|
.collect(Collectors.groupingBy(BaseResponse::getStatus));
|
||||||
|
|
||||||
|
addErrorCodesToResponse(responses, statusWithErrorResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
//ApiResponses에 error response 추가
|
||||||
|
private void addErrorCodesToResponse(ApiResponses apiResponses, Map<Integer, List<BaseResponse<CustomError>>> responses) {
|
||||||
|
responses.forEach((status, value) -> {
|
||||||
|
Content content = new Content();
|
||||||
|
MediaType mediaType = new MediaType();
|
||||||
|
ApiResponse apiResponse = new ApiResponse();
|
||||||
|
|
||||||
|
value.forEach(
|
||||||
|
errorInfoResponse -> {
|
||||||
|
Example example = new Example();
|
||||||
|
example.setValue(errorInfoResponse);
|
||||||
|
mediaType.addExamples(String.valueOf(errorInfoResponse.getCode()), example);
|
||||||
|
});
|
||||||
|
|
||||||
|
content.addMediaType("application/json", mediaType);
|
||||||
|
apiResponse.setContent(content);
|
||||||
|
apiResponses.addApiResponse(String.valueOf(status), apiResponse);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.worlabel.global.config.swagger;
|
||||||
|
|
||||||
|
import com.worlabel.global.exception.ErrorCode;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target({ElementType.METHOD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface SwaggerApiError {
|
||||||
|
|
||||||
|
ErrorCode[] value();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.worlabel.global.config.swagger;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target({ElementType.METHOD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@ApiResponses(value = {
|
||||||
|
@ApiResponse(responseCode = "200")
|
||||||
|
})
|
||||||
|
public @interface SwaggerApiSuccess {
|
||||||
|
|
||||||
|
String description() default "";
|
||||||
|
}
|
||||||
|
|
@ -22,6 +22,11 @@ public abstract class BaseResponse<T> {
|
|||||||
@Getter(onMethod_ = @JsonProperty("isSuccess"))
|
@Getter(onMethod_ = @JsonProperty("isSuccess"))
|
||||||
private boolean isSuccess;
|
private boolean isSuccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 상태 코드
|
||||||
|
*/
|
||||||
|
private int status;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 응답 코드
|
* 응답 코드
|
||||||
*/
|
*/
|
||||||
@ -42,8 +47,9 @@ public abstract class BaseResponse<T> {
|
|||||||
*/
|
*/
|
||||||
protected List<CustomError> errors;
|
protected List<CustomError> errors;
|
||||||
|
|
||||||
public BaseResponse(boolean isSuccess, int code, String message) {
|
public BaseResponse(boolean isSuccess, int status, int code, String message) {
|
||||||
this.isSuccess = isSuccess;
|
this.isSuccess = isSuccess;
|
||||||
|
this.status = status;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.data = null;
|
this.data = null;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.worlabel.global.response;
|
package com.worlabel.global.response;
|
||||||
|
|
||||||
import com.worlabel.global.exception.CustomException;
|
import com.worlabel.global.exception.CustomException;
|
||||||
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.validation.Errors;
|
import org.springframework.validation.Errors;
|
||||||
@ -16,19 +17,22 @@ import java.util.stream.Collectors;
|
|||||||
* 에러 발생시 리턴 할 에러 응답 객체
|
* 에러 발생시 리턴 할 에러 응답 객체
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ErrorResponse extends BaseResponse<Void> {
|
@Getter
|
||||||
|
public class ErrorResponse extends BaseResponse<CustomError> {
|
||||||
|
|
||||||
public ErrorResponse(boolean isSuccess, int code, String message, Errors errors) {
|
|
||||||
super(isSuccess, code, message);
|
|
||||||
|
public ErrorResponse(boolean isSuccess, int status, int code, String message, Errors errors) {
|
||||||
|
super(isSuccess, status, code, message);
|
||||||
super.errors = parseErrors(errors);
|
super.errors = parseErrors(errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ErrorResponse(CustomException exception) {
|
public ErrorResponse(CustomException exception) {
|
||||||
this(false, exception.getErrorCode().getCode(), exception.getMessage(), exception.getErrors());
|
this(false, exception.getErrorCode().getStatus().value(), exception.getErrorCode().getCode(), exception.getMessage(), exception.getErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ErrorResponse(CustomException exception, String message) {
|
public ErrorResponse(CustomException exception, String message) {
|
||||||
this(false, 1, message, exception.getErrors());
|
this(false, exception.getErrorCode().getStatus().value(), 1, message, exception.getErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ErrorResponse of(CustomException exception) {
|
public static ErrorResponse of(CustomException exception) {
|
||||||
@ -40,7 +44,7 @@ public class ErrorResponse extends BaseResponse<Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ErrorResponse of(Exception exception) {
|
public static ErrorResponse of(Exception exception) {
|
||||||
return new ErrorResponse(false, HttpStatus.INTERNAL_SERVER_ERROR.value(), exception.getMessage(), null);
|
return new ErrorResponse(false, HttpStatus.INTERNAL_SERVER_ERROR.value(), HttpStatus.INTERNAL_SERVER_ERROR.value(), exception.getMessage(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,7 +17,7 @@ public class SuccessResponse<T> extends BaseResponse<T> {
|
|||||||
* 성공 응답 객체 생성자
|
* 성공 응답 객체 생성자
|
||||||
*/
|
*/
|
||||||
public SuccessResponse() {
|
public SuccessResponse() {
|
||||||
super(true, HttpStatus.OK.value(), "success");
|
super(true, HttpStatus.OK.value(), 200, "success");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,7 +26,7 @@ public class SuccessResponse<T> extends BaseResponse<T> {
|
|||||||
* @param data 성공시 반환하는 데이터
|
* @param data 성공시 반환하는 데이터
|
||||||
*/
|
*/
|
||||||
public SuccessResponse(T data) {
|
public SuccessResponse(T data) {
|
||||||
super(true, 200, "success");
|
super(true, 200, 200, "success");
|
||||||
super.data = data;
|
super.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user