Swagger란 개발한 REST API를 편리하게 문서화해주고, 이를 통해서 관리 및 제3의 사용자가 편리하게 API를 호출해보고 테스트 할 수 있는 API 문서 라이브러리이다.
Spring Boot에서는 간단하게 springfox-boot-starter 를 maven, gradle dependencies에 추가함으로 사용할 수 있다.
다만, 주의할 점은 운영환경과 같은 외부에 노출되면 안되는 곳에는 사용하면 안된다.
🥲 상당히... SpringBoot 버전이 올라가면서 기존의 버전들이 안되는 일이 많은 Swagger... ㅜ 이번 기회에 정리해본다.
정리는 최신버전순으로 정리할려고 한다.
// Swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'
SwaggerConfig
package com.example.surl241112.config;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI openAPI() {
return new OpenAPI()
.openapi("3.0.0") // openAPI 버전 명시
.components(new Components())
.info(apiInfo());
}
private Info apiInfo() {
return new Info()
.title("CodeArena Swagger")
.description("CodeArena 유저 및 인증 , ps, 알림에 관한 REST API")
.version("1.0.0");
}
}
TestController
@Tag
- Controller 단@Operation
- Method 단package com.example.surl241112.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
@Tag(name = "test", description = "test 컨트롤러에 대한 설명입니다.")
public class TestController {
@Operation(summary = "test 문자열", description = "test 문자열 설명입니다.")
@GetMapping
public Object test() {
return "test";
}
}
http://localhost:8080/swagger-ui/index.html
http://localhost:8080/v3/api-docs
💡 참고하면 좋은 영상 - https://www.youtube.com/watch?v=3QQvpu7NqlE
@Bean
public OpenAPI openAPI() {
return new OpenAPI().openapi("3.0.0") // openAPI 버전 명시
.components(new Components()
.addSecuritySchemes("jwt-token",
new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")
.in(SecurityScheme.In.HEADER).name("Authorization")))
.addSecurityItem(new SecurityRequirement().addList("jwt-token"))
.info(apiInfo());
}
JWTCheckFilter
@Log4j2
public class JWTCheckFilter extends OncePerRequestFilter {
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
String path = request.getRequestURI();
log.info("check uri: " + path);
// Pre-flight 요청은 필터를 타지 않도록 설정
if (request.getMethod().equals("OPTIONS")) {
return true;
}
// /api/member/로 시작하는 요청은 필터를 타지 않도록 설정
if (path.startsWith("/api/member/")) {
return true;
}
...
// Swagger UI 경로 제외 설정
if (path.startsWith("/swagger-ui/") || path.startsWith("/v3/api-docs")) {
return true;
}
return false;
}
SecurityConfig
💥 이것을 해주어야 Access Denied 에러가 안뜬다!
http.authorizeHttpRequests(
authorizeHttpRequests -> authorizeHttpRequests
// /favicon.ico 경로 제외 설정
// .requestMatchers(new AntPathRequestMatcher("/favicon.ico")).permitAll()
// h2-console 경로 제외 설정
.requestMatchers(new AntPathRequestMatcher("/h2-console/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/swagger-ui/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/v3/api-docs/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/api/member/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/api/products/view/*")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/api/test/**")).permitAll()
.anyRequest().authenticated()
);
id 'org.springframework.boot' version '2.4.4'
springboot 2버전 기준
springfox-swagger2
, springfox-swagger-ui
2개 디팬더시가 필요하다.
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
// https://mvnrepository.com/artifact/io.springfox/springfox-swagger2
implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
(오류)
update: Swagger3 버전
위 버전의 디팬더시를 쓰면 springboot 버전을 낮춰야지만 사용할 수있다.
다음 3버전부터 쓰면 그럴 필요가 없다.
implementation 'io.springfox:springfox-boot-starter:3.0.0'
💥 documentationPluginsBootstrapper
- Swagger3 버전 dependacy 추가 후 오류
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
원인 : Spring boot 2.6버전 이후에 spring.mvc.pathmatch.matching-strategy 값이 ant_apth_matcher에서 path_pattern_parser로 변경되면서 몇몇 라이브러리에서 오류가 발생한다고 한다.
해결 : application.yml에 아래와 같은 줄 추가
application.yml
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
http://localhost:8090/swagger-ui.html
을 웹브라우저에 치면 나온다.http://localhost:8080/v2/api-docs
http://localhost:8090/swagger-ui/index.html
✅ 이 어노테이션이 안붙인다고 swagger ui에 각 api url 표시가 안나오지는 않습니다!
@Api
: 클래스
를 swagger의 리소스로 표시(표시 나오는 부분이 없음)
@ApiOperation
: 메서드
를 swagger의 리소스로 표시
@ApiResponse
: 메서드
의 응답 지정
@Api(value = "comment controller exposes crud rest-apis")
@RestController
@RequestMapping("/api/")
@RequiredArgsConstructor
public class CommentController {
@ApiOperation(value="AI 전기방식 동작여부 확인", notes="시스템에 등록된 현재 AI 전기방식 상태값 리턴(state:'Y' or 'N'). '../set-state'가 일정 시간 호출되지 않을 경우 N을 리턴.")
@ApiResponses({
@ApiResponse(code = 200, message = "API 정상 작동"),
@ApiResponse(code = 500, message = "서버 에러")
})
@RequestMapping(value="/is-running", method={RequestMethod.GET})
public ResponseEntity<AIRunningVo> isRunning() throws Exception {
AIRunningVo res = new AIRunningVo();
res.setState(AiStateManager.getInstance().getState());
return new ResponseEntity<AIRunningVo>(res, HttpStatus.OK);
}
...
}
빨간색 박스 내용이 @ApiOperation
표시이다.
@ApiModel
: 모델의 데이터 설명
@ApiModelProperty
: 모델의 필드 데이터를 설명
@ApiModel(description = "board AmiDeviceAddVo information")
@Data
@NoArgsConstructor
public class SignUpDto {
@ApiModelProperty(value = "사용자 이름", dataType = "string", required = true, example = "롬복")
private String name;
@ApiModelProperty(value = "사용자 이메일")
private String email;
private String password;
private String role;
}
@ApiModelProperty
내 옵션으로 example
을 설정해주면 Swagger문서의 Example Value 로 나오게 된다!
그리고 그 옆에 Schema 쪽을 누르면 RequestBody로 넣을 클래스 정리가 된 것을 알 수 있다.
swagger 문서 맨 아래 쪽을 가서 Schemas
탭을 눌러서도 정리가 된 것도 알 수 있다.
이 Schemas 탭을 누르고 ~Dto
를 검색(ctrl+F)해서 Dto 정보를 빨리 찾아볼 수있다!
SwaggerConfig
: @EnableSwagger2
사용
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("springBoot-swagger-example ")
.description("description")
.version("1.0")
.build();
}
}
Swagger3 버전
@Configuration
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.OAS_30)
.useDefaultResponseMessages(false)
.select()
.apis(RequestHandlerSelectors.basePackage("com.dsg.wardstudy.controller"))
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("swagger-api-Docs")
.description("SwaggerConfig")
.version("1.0") // 문서 버전 관리
.build();
}
}
SecurityConfig있을시 (swagger api 허용 설정)
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
"/v2/api-docs",
"/swagger-resources/**",
"/swagger-ui.html",
"/webjars/**",
"/swagger/**",
"/v3/api-docs/**",
"/swagger-ui/**",
"/robot.txt",
"/favicon.ico"
);
}
Authorization (apiKey) 설정
Bearer
{accessToken}
을 넣어줘서 인증을 받아야 한다.
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.ignoredParameterTypes(AuthenticationPrincipal.class)
.securityContexts(Arrays.asList(securityContext()))
.securitySchemes(Arrays.asList(apiKey()))
.useDefaultResponseMessages(false)
... // 추가
}
// 추가
private ApiKey apiKey() {
return new ApiKey("Authorization", "Authorization", "header");
}
private SecurityContext securityContext() {
return SecurityContext
.builder()
.securityReferences(defaultAuth()).forPaths(PathSelectors.any()).build();
}
List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return Arrays.asList(new SecurityReference("Authorization", authorizationScopes));
}
Try it out
을 누른 다음 Parm 등 value
채우고
Execute
클릭 하면 Response를 확인할 수 있다.
결과(예시로 Response Body, Response Code 등)
👍 POST일시
특히, Swagger를 쓰는 이유 중에 POST방식을 사용하는데 RequestBody
를 지정해주는 것이 편하기 때문인데, 아래 사진을 보면
자동으로 Request Body 필드 들을 생성해주는 것을 볼 수 있다.
이처럼 개발자는 편한게 필드에 대한 내용만 적어 주면 되는 것
이다. 이젠, postman에서 다 작성해야 하는 번거로운 일을 하지 않아도 되는 것이다.