SpringBoot Swagger 설정(3버전 추가)

devdo·2021년 12월 31일
0

SpringBoot

목록 보기
12/35
post-thumbnail

Swagger란?

Swagger란 개발한 REST API를 편리하게 문서화해주고, 이를 통해서 관리 및 제3의 사용자가 편리하게 API를 호출해보고 테스트 할 수 있는 API 문서 라이브러리이다.

Spring Boot에서는 간단하게 springfox-boot-starter 를 maven, gradle dependencies에 추가함으로 사용할 수 있다.

다만, 주의할 점은 운영환경과 같은 외부에 노출되면 안되는 곳에는 사용하면 안된다.

🥲 상당히... SpringBoot 버전이 올라가면서 기존의 버전들이 안되는 일이 많은 Swagger... ㅜ 이번 기회에 정리해본다.

정리는 최신버전순으로 정리할려고 한다.


업데이트(SpringBoot3 + Swagger 3)

// 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


Jwt 추가 설정

@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());
    }

Secuirty6 swagger 설정

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()
        );


Swagger 2 버전

설정

springboot version

id 'org.springframework.boot' version '2.4.4'

maven repository


dependacy

springboot 2버전 기준
springfox-swagger2, springfox-swagger-ui 2개 디팬더시가 필요하다.

  • maven
<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>
  • gradle
// 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

웹 브라우저 확인

  • swagger 2
    http://localhost:8090/swagger-ui.html을 웹브라우저에 치면 나온다.

  • http://localhost:8080/v2/api-docs

  • swagger 3
    http://localhost:8090/swagger-ui/index.html

어노테이션

✅ 이 어노테이션이 안붙인다고 swagger ui에 각 api url 표시가 안나오지는 않습니다!

Controller 단

@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 표시이다.

Dto(Request) 단

@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에서 다 작성해야 하는 번거로운 일을 하지 않아도 되는 것이다.



참고

profile
배운 것을 기록합니다.

0개의 댓글