반응형

정의

Swagger UI란 Swagger 제품군 중 API Documentation과 관련된 기능을 제공하는 제품이다.

Swagger 홈페이지에 등록된 Swagger UI에 대한 설명은 다음과 같다.

 

Swagger UI allows anyone — be it your development team or your end consumers — to visualize and interact with the API’s resources without having any of the implementation logic in place. It’s automatically generated from your OpenAPI (formerly known as Swagger) Specification, with the visual documentation making it easy for back end implementation and client side consumption.
Swagger UI를 사용하면 개발 팀이든 엔드 유저든 누구나 구현 로직 없이도 API 리소스를 시각화하고 상호 작용할 수 있도록 도와줍니다. Swagger는 OpenAPI (이전 Swagger) 사양으로 자동 생성되며 시각적 문서를 통해 백엔드 구현 및 클라이언트 측 사용을 쉽게 할 수 있게 합니다.

 

즉, Swagger UI를 적용하면 별도의 코드 추가 없이도 OpenAPI 규격에 맞게 API를 자동으로 시각화 시켜 줄 수 있다.

 

https://swagger.io/tools/swagger-ui/


 

예제 환경

  • spring boot 2.5.2
  • gradle
  • swagger ui 2.9.2
  • ModelMapper 2.3.8
  • src 구성
     
    • SwaggerConfig.java : Swagger 설정 파일
    • OrderController.java : API Controller 파일
    • OrderRequest/Response: 송/수신 DTO 파일
    • Order : Order 엔티티 파일
    • OrderDB: Order 엔티티를 저장, 관리를 위한 임시 DB
    • OrderRepository/*Impl : DB 조작용 Repository
    • OrderService/*Impl: 비즈니스 로직 처리용 Service

 

Gradle dependency 추가

  • implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
  • implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'

 

Swagger UI 환경 설정 파일 추가

  • swagger ui를 사용하기 위해선 dependency 추가와 아래의 설정 파일만 작성하면 Controller에 등록된 API를 자동으로 읽어 올 수 있다.

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;

    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
        @Bean
        public Docket swagger() {
            return new Docket(DocumentationType.SWAGGER_2)
                    .select()
                    .apis(RequestHandlerSelectors.any())
                    .paths(PathSelectors.any())
                    .build();
        }
    }
  • @EnableSwagger2 : Swagger2 활성화
  • public Docket api() : Swagger API 설정
    • ParameterBuilder
      • API를 테스트할때 모든 API에 전역 파라미터를 설정
      • 아래의 예시 처럼 모든 API 테스트시 header에 'Autorization' 이라는 값을 추가 할 수도 있음
    • useDefaultResponseMessages()
      • false로 설정하면, swagger에서 제공해주는 응답코드  200,401,403,404 )에 대한 기본 메시지 제거
      • 불필요한 응답코드와 메시지를 제거하기 위함이며, 컨트롤러에서 명시
    • groupName()
      • Docket이 한 개일 경우 기본 값 default이므로 생략 가능 하지만, Docket을 여러개 사용 할 경우 groupName이 충돌하지 않도록 지정해야 함
    • select()
      • ApiSelectorBuilder를 생성
    • apis()
      • api 스펙이 작성되어 있는 패키지를 지정 함.
      • 즉, 컨트롤러가 존재하는 패키지를 basepackage로 지정하여, RequestMapping( GetMapping, PostMapping ... )이 선언된 API를 문서화 함
    • paths()
      • apis()로 선택되어진 API중 특정 path 조건에 맞는 API들을 다시 필터링하여 문서화
    • apiInfo()
      • 제목, 설명 등 문서에 대한 정보들을 보여주기 위해 호출.
      • 사용되는 파라미터 정보는 다음과 같음
        public ApiInfo( title, description, version, termsOfServiceUrl, contact, license, licenseUrl, vendorExtensions )
    • 예시

      @Configuration
      @EnableSwagger2
      public class SwaggerConfig {
          private String version;
          private String title;

          @Bean
          public Docket apiV1() {
              version = "V1";
              title = "Swagger Example API " + version;

              Parameter parameterBuilder = new ParameterBuilder()
                  .name(HttpHeaders.AUTHORIZATION)
                  .description("Access Token")
                  .modelRef(new ModelRef("string"))
                  .parameterType("header")
                  .required(false)
                  .build();

              List<Parameter> globalParamters = new ArrayList<>();
              globalParamters.add(parameterBuilder);

              return new Docket(DocumentationType.SWAGGER_2)
                      .globalOperationParameters(globalParamters)
                      .useDefaultResponseMessages(false)
                      .groupName(version)
                      .select()
                      .apis(RequestHandlerSelectors.basePackage("com.example.swagger.v1"))
                      .paths(PathSelectors.ant("/v1/customer/**"))
                      .build()
                      .apiInfo(apiInfo(title, version));

          }

          @Bean
          public Docket apiV2() {
              version = "V2";
              title = "Swagger Example API " + version;

              return new Docket(DocumentationType.SWAGGER_2)
                      .useDefaultResponseMessages(false)
                      .groupName(version)
                      .select()
                      .apis(RequestHandlerSelectors.basePackage("com.example.swagger.v2"))
                      .paths(PathSelectors.ant("/v2/customer/**"))
                      .build()
                      .apiInfo(apiInfo(title, version));

          }

          private ApiInfo apiInfo(String title, String version) {
              return new ApiInfo(
                      title,
                      "Swagger로 생성한 API Docs",
                      version,
                      "www.example.com",
                      new Contact("Contact us", "www.example.com", "sharplee7@gmail.com"),
                      "Licenses",
                      "www.example.com",
                      new ArrayList<>());
          }
      }

 

예제 Controller 클래스 작성

  • 별도의 코드 추가 없이 기존 Controller 클래스 작성하는 방법과 동일

    @RestController
    public class OrderController {
        @Autowired
        OrderService orderService;
        // DTO to Entity, Entity to DTO를 위해 ModelMapper 사용
        ModelMapper modelMapper = new ModelMapper();

        @PostMapping("/order")
        public int saveOrder(@RequestBody OrderRequest orderRequest) {
            // ModelMapper를 이용해 OrderRequest DTO의 값을 Order Entity로 복사한다.
            Order order = modelMapper.map(orderRequest, Order.class);
            return orderService.save(order);
        }

        @PutMapping("/order")
        public int changeOrder(@RequestBody OrderRequest orderRequest) {
            // ModelMapper를 이용해 OrderRequest DTO의 값을 Order Entity로 복사한다.
            Order order = modelMapper.map(orderRequest, Order.class);
            return orderService.modify(order);
        }

        @DeleteMapping("/order/{id}")
        public int deleteOrder(String id) {
            return orderService.delete(id);
        }

        @GetMapping("/order/{id}")
        public OrderResponse getOrder(@PathVariable String id) {
            Order order = orderService.findById(id);
            // ModelMapper를 이용해 order entity의 값을 OrderResponse DTO로 변환한다.
            OrderResponse orderResponse = modelMapper.map(order, OrderResponse.class);

            return orderResponse;
        }

        @GetMapping("/order")
        public List getOrders() {
            // Persistence에서 List로 생성된 Entity 리스트를 화면으로 전달하기 위해 List로 변환
            List postDtoList = Arrays.asList(modelMapper.map(orderService.findAll(), OrderResponse[].class));
            return postDtoList;
        }
    }
  • @ApiOperation 어노테이션을 API에 추가해 API에 대한 주석을 달 수 있음(옵션)

    @ApiOperation(value="Order 정보 생성", notes="Order 정보, 수량, 상태를 입력해 Order 정보를 생성한다.")
    @PostMapping("/order")
    public int saveOrder(@RequestBody OrderRequest orderRequest) {
        Order order = modelMapper.map(orderRequest, Order.class);
        return orderService.save(order);
    }
    @ApiOperation 적용 전/후 비교

그외 : Response용 DTO 작성 (옵션)

  • @ApiModelProperty 
    • @ApiModelProperty 어노테이션을 응답으로 제공되는 DTO 객체의 속성(Property)에 추가해 응답되는 데이터의 포맷에 대해 설명을 할 수 있다.(보통 응답 값을 알 수 없는 경우가 많은데, 이 속성을 통해 응답 받는 데이터의 구조를 쉽게 알 수 있다.)

      public class OrderResponse {

          @ApiModelProperty(example = "Order id")
          private String id = null;

          @ApiModelProperty(example = "주문 수량")
          private int quantity = 0;

          @ApiModelProperty(example = "주문 일자")
          private String date = null;

          @ApiModelProperty(example = "주문 상태")
          private String status = null;

          @ApiModelProperty(example = "주문 완료 여부")
          private boolean complete = false;
      @ApiModelProperty 어노테이션 적용시 리스폰스 데이터 형식 가이드

 

웹 브라우저를 통해 호출

  • 웹 브라우저를 시작 한 후 http://localhost:8080/swagger-ui.html을 호출 한다.
  • Order Contoller의 모든 API들이 표시된다.
  • Try it out을 클릭해 테스트 데이터를 입력 한 후 Execute를 실행하면 실행 결과가 표시 된다.

 

예제소스 링크

이 포스팅에서 사용된 예제 소스는 https://github.com/sharplee7/swagger-demo.git 에서 참조 할 수 있다.

git checkout v1.0 이 경우 기본 예제

git checkout v2.0 이 경우 확장 예제

 

반응형

'Application Modernization > Others' 카테고리의 다른 글

현재 OS에 열린 포트 확인  (0) 2021.10.13
REST API 설계 가이드  (0) 2021.07.11

+ Recent posts