250x250
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- 그리드
- ci/cd
- mssql
- ORM
- MessageQueue
- 자바8
- rabbitmq
- Javascript
- QueryDSL
- apache.poi
- poi
- java
- 대용량 업로드
- 제이쿼리그리드
- Stream
- DevOps
- JPA
- sqlserver
- 자동빌드
- JQuery
- 자동배포
- spring
- jqGrid
- 엑셀 업로드
- stream api
- mom
- docker
- 보안
- 스트림
- Jenkins
Archives
- Today
- Total
개발 메모장
[Spring] Swagger 3.0 - API 문서화 본문
728x90
- 데이터 수신을 위한 API 개발을 위해 이전 테스트한 Swagger보다 좀 더 나아간 Swagger 개발을 해야하는 업무가 생겼습니다.
- 클라이언트에게 변경사항이 생길 때마다 알려주는 것보다 API문서화하여 처리하는 편이 멀리 봤을 때 간편하다고 생각하여 아래와 같이 처리하였습니다.
#. dependency 추가
- Swagger 3 버전을 사용합니다.
implementation 'io.springfox:springfox-boot-starter:3.0.0'
implementation 'io.springfox:springfox-swagger-ui:3.0.0'
#. SwaggerConfig
- Swagger 사용을 위한 Configuration 및 Bean 설정을 합니다.
- Docket > securityContexts 및 securitySchemes를 제외하면 Swagger에 Authorize 버튼이 생성되지 않으니 참고바랍니다.
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.OAS_30)
// 인증 관련(추가 시 Authorize 버튼 생성)
.securityContexts(Arrays.asList(securityContext()))
.securitySchemes(Arrays.asList(apiKey()))
.useDefaultResponseMessages(false)
.select()
// 1개의 특정 경로 지정 시
.apis(RequestHandlerSelectors.basePackage("com.test.tt.test1.controller"))
// 두개 이상의 경로 지정 시
//.apis(multipleBasePackages(
// "com.test.tt.test1.controller",
// "com.test.tt.test2.controller"
// ))
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
// API 정보 입력
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Test API Swagger")
.description("test swagger")
.version("1.0")
.build();
}
// Swagger 보안 체계 적용
private SecurityContext securityContext() {
return SecurityContext.builder()
// API에 적용될 보안 권한 범위 설정
.securityReferences(defaultAuth())
.build();
}
// 기본 인증 범위 설정
private List<SecurityReference> defaultAuth() {
// OAuth2 보안 범위 설정
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
// 인증 범위를 배열에 넣기
authorizationScopes[0] = authorizationScope;
// 인증 범위에 대한 객체 생성 및 리스트로 변환
return Arrays.asList(new SecurityReference("Authorization", authorizationScopes));
}
// Swagger가 요청 시 승인하는 API키 구성
private ApiKey apiKey() {
return new ApiKey("Authorization", "Bearer", "header");
}
// Swagger에 다중 경로 지정 시
private Predicate<RequestHandler> multipleBasePackages(String... basePackages) {
return input -> {
Class<?> declaringClass = input.declaringClass();
for (String basePackage : basePackages) {
if (declaringClass.getPackage().getName().startsWith(basePackage)) {
return true;
}
}
return false;
};
}
}

#. WebMvcConfig(Swagger 경로를 읽지 못할 때)
- 서비스 중인 기존 프로젝트 내 Swagger를 추가하다보니 기존 설정으로 인해 정상적으로 처리되지 않았습니다.
- Unable to infer base Url ... 이런 에러가 발생하였고 URL 관련이라 생각이 들어 찾아보니 아래와 같은 방법으로 핸들러에 uri 값을 넣어줘야 했습니다.

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private HttpInterceptor httpIndenter;
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
// 기존
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/templates/", "classpath:/static/")
.setCacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES));
// swagger
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(httpIndenter)
.addPathPatterns("/**")
.excludePathPatterns(
// swagger 관련 URI 추가
"/swagger-ui/**",
"/swagger-resources/**",
"/v2/api-docs",
"/webjars/**"
);
}
}
#. Interceptor
- 기존 로직에서 특정 URI만 통과될 수 있도록 Interceptor에 설정돼 있었습니다.
- 따라서 Interceptor에 화면에 나온 undefined uri를 예외 처리하여 접근 가능토록 하였습니다.
- 접속 uri은 swagger-ui지만 getRequestURI()로 전달 받은 uri는 /v3/api-docs로 받으니 참고하도록 바랍니다.
- 인증 받지 않은 이용자의 경우 API를 통신하지 못하도록 막아주는 로직도 추가합니다.
(보통 자바의 경우 jjwt 라이브러리를 이용해 발급 및 유효여부 체크를 합니다. 현재 로직은 테스트용으로 하드코딩한 Key로 간단히 작성했습니다.)

@Component
public class HttpInterceptor implements HandlerInterceptor {
// Authorize를 위한 key 지정
private static final String API_KEY = "test123";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
// swagger
if(requestURI.indexOf("/v3/api-docs") >= 0) {
return true;
}
if(requestURI.startsWith("/api/v1/")) {
String authHeader = request.getHeader("Authorization");
if(authHeader == null || "".equals(authHeader)) {
throw new CommonException(HttpStatus.UNAUTHORIZED, ReturnCode.INVALID_TOKEN, "인증키가 없습니다.");
}
if(!authHeader.equals(API_KEY)) {
throw new CommonException(HttpStatus.UNAUTHORIZED, ReturnCode.INVALID_TOKEN, "잘못된 인증키입니다.");
}
return true;
}
}
}
728x90
#. Controller 세부 설정
- SwaggerConfig에서 기본적인 설명을 명시하고 컨트롤러에서 어노테이션을 추가해 세부적인 설명을 명시할 수 있습니다.
@RestController
@RequestMapping("/api/v1")
@Api(tags="testApi")
@Tag(name="testApi", description="테스트 API")
public class TestController {
@Autowired
private TestService testService;
@ApiOperation("테스트 데이터 송신")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "성공했습니다! Success", content = @Content(schema = @Schema(implementation = TestVO.class))),
@ApiResponse(responseCode = "404", description = "실패했습니다! Falied", content = @Content(schema = @Schema(implementation = TestVO.class))) })
@PostMapping("/testApi")
@Transactional
public ResponseEntity<?> setTestData(@RequestBody TestVO param) {
testService.setTestData(param);
// 미리 정의한 성공 시 리턴코드 및 메시지를 리턴해줍니다.
return ResponseEntity.ok(new ResponseData(ReturnCode.SUCCESS, Message.get(Message.REG_SUCCESS)));
}
}


- 그 외의 태그들은 아래 참조 링크를 참고 바랍니다.
#. VO > @schema
- 데이터들의 타입 및 설명을 작성하여 서로 이해할 수 있게 도와줍니다.
- validation 라이브러리를 추가해 @NotNull 이나 @NotBlank 등으로 빈값 및 null 체크를 해주면 좋습니다.
- 아래 내용은 위 그림파일의 Schema 내용에 적용됩니다.
@Data
public class TestVO {
private List<test> testList;
@Data
public static class test {
@Schema(description = "테스트1", required = true)
private String test1;
@Schema(description = "테스트2", required = true)
private int test2;
@Schema(description = "테스트3", required = true)
private int test3;
@Schema(description = "테스트4", required = true)
private int test4;
@Schema(description = "테스트5", required = true)
private String test5;
@Schema(description = "테스트6", required = true)
private String test6;
@Schema(description = "테스트7", required = true)
private int test7;
@Schema(description = "테스트8", required = true)
private String test8;
}
}
===========================================================
틀린 내용이 있거나 이견 있으시면 언제든 가감 없이 말씀 부탁드립니다!
참조 : https://docs.swagger.io/swagger-core/v1.5.0/apidocs/
===========================================================
728x90
'Spring' 카테고리의 다른 글
[Spring] Swagger(스웨거) 사용방법 (0) | 2024.02.19 |
---|---|
[Spring] 스프링 시큐리티(Spring Security) (0) | 2024.02.07 |