티스토리 뷰

지난번에 했던건 그저 API 호출을 하면 Hello,World를 뱉어내는 아주 단순한 API를 만들어냈다.

사실 어떤 웹서비스를 만들고 그 서비스를 이용하기 위해서는 꽤 많은 양의 API들이 필요하고 그 API를 정리하는데에 시간을 소모하게 된다.

내가 만약 아주 단순한 서비스를 만든다고 가정했을 때(아직 OAuth를 배우진 않았으니까 OAuth가 없다고 가정하고) 일반적으로 예상할 수 있는 API의 종류는 아래와 같을 것이다.


  • 이메일 중복확인
  • 회원가입
  • 로그인
  • 개인정보 수정
  • 패스워드 수정(개인정보 수정에 포함 가능)
  • 회원 탈퇴
  • 파일 업로드
  • 파일 다운로드(다운로드 관련 기능이 별도로 필요하다면)
  • 글 쓰기
  • 글 수정하기
  • 글 삭제하기
  • 글 목록 가져오기
  • 글 읽기

이 정도 기능이면 아주아주 단순한 게시판 하나 달랑있는 사이트를 만들어 낼 수 있다.

아, 위 기능은 서버에서 처리할 API 종류에 대한 이야기다. 최소한의 기능들의 목록이며 나머지 사이트들의 경우 이 기능들에서 살을 덧붙여 만들거나 위 기능의 반복 수준에서 소규모에서 중규모 사이트까지 만들어 낼 수 있다.

물론 이런 기본 기능 외에 다른 특수한 기능들을 제공 받기를 원할 수 있는데 이것은 대부분 Frontend 단에서 적용이 가능하거나 Backend의 기능 확장이 필요한 경우가 있을 수 있다. 내가 여기에서 이야기하고 싶은 부분은 저 위의 기능은 사이트를 구성하는 아주 아주 최소한의 기능뿐이라는 거다.

그리고 관리자 기능은 넣지도 않았다. 관리자 기능을 넣으면 회원관리기능이라던지 게시물 관리기능 정도가 붙겠지만 사실 위 기능의 확장이거나 응용이 전부라는 점에서 큰 이슈사항이 없을것이라고 생각한다. 물론 통계라던지 태그를 이용한 검색이라던지 하는 특수한 기능들도 있겠지만 내가 하려는건 어디까지나 "단순한" 사이트니까.


일단 이 정도의 기능으로 사이트를 만들고 그 뒤에 추가 기능을 덧붙인다고 생각하고 진행한다.

오늘은 저번에 만든 프로젝트에 Swagger라는 기능을 붙일 생각인데 이 기능이 무엇이냐하면 Controller에서 API를 만들면 이것을 문서화하는 일이 굉장히 귀찮다. 뭐 엑셀로 할지, 혹은 워드로 정리할지 문서화하는 일은 중요하지만 귀찮은 일임에는 틀림이 없다. 그래서 그걸 대신작업을 해주는 녀석이 이 Swagger라는 라이브러리다.

이 라이브러리는 서버가 올라갈때 자동으로 RestController어노테이션을 읽어서 내부의 API를 분석하고 HTML 문서를 작성해 서비스를 제공해준다. 셋팅작업을 진행해보자.


일단 https://swagger.io/ 사이트에 가본다.



이런 페이지가 나온다. 세상에서 가장 유명한 API 툴이라며 광고를 했다. 이것은 Open Source고 무료로 적용할 수 있다. 내용을 읽어보니 뭐 좋은 내용들이다. 무료고 오픈소스고 라이센스가 어떻고 디자인이나 빌드나 Document도 어떻고...

그런데 문제는 이걸 어떻게 우리 프로젝트에 적용해야 하는가에 대한 것은 어디있느냐는 거다.


그래서 구글링을 좀 했더니 http://www.baeldung.com/swagger-2-documentation-for-spring-rest-api 사이트에 설명이 잘 되어 있는 것을 확인했다.

Maven Dependency를 통해 생성하는 것부터 잘 따라서 작업해보자.



<dependency>
    <groupid>io.springfox</groupid>
    <artifactid>springfox-swagger2</artifactid>
    <version>2.7.0</version>
</dependency>
<dependency>
    <groupid>io.springfox</groupid>
    <artifactid>springfox-swagger-ui</artifactid>
    <version>2.7.0</version>
</dependency>


먼저 swagger2 라이브러리를 pom.xml의 dependency 쪽에 추가하자.


그리고 SwaggerConfig라는 클래스를 만든다. 나는 config 패키지를 하나 추가해서 거기에 SwaggerConfig 클래스를 만들었다.



이렇게 했으면 몇가지 코드를 추가하는데 아래와 같이 준비한다.



package com.example.sample.config;

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 api() { 
        return new Docket(DocumentationType.SWAGGER_2)  
          .select()                                  
          .apis(RequestHandlerSelectors.any())              
          .paths(PathSelectors.any())                          
          .build();                                           
    }
}


이렇게 작성하면 일단 Swagger 설정은 마쳤다. 

이렇게 하고 서버를 시작해보자.



이러면 위 사진처럼 Swagger관련 API들이 로그에 찍힌 것을 확인할 수 있다.

조금 더 설정 정보를 추가할 수 있다.



package com.example.sample.config;

import java.util.Collections;

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.service.ApiInfo;
import springfox.documentation.service.Contact;
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 api() { 
        return new Docket(DocumentationType.SWAGGER_2)  
          .select()                                  
          .apis(RequestHandlerSelectors.basePackage("com.example.sample.controller") )              
          .paths(PathSelectors.any())                          
          .build()
          .apiInfo(apiInfo());
    }
    
    private ApiInfo apiInfo() {
        return new ApiInfo(
          "Hello REST API", 
          "Some custom description of API.", 
          "API TOS", 
          "Terms of service", 
          new Contact("야훔", "www.example.com", "myeaddress@company.com"), 
          "License of API", "API license URL", Collections.emptyList());
   }
}


이렇게 작업을 해 놓고 http://localhost:8080/swagger-ui.html 페이지를 한번 확인해보자.


요런 화면이 나오고  우리가 만든 hello API가 자동으로 확인되어 화면에 표시해준다.


그리고 API 주소를 클릭하면 조금 더 상세 정보를 확인할 수 있고 "Try it out!" 버튼을 클릭하면 XHR로 API를 호출한 결과를 알려준다.


Controller에 아래와 같이 주석처리를 하면 Swagger UI에 설명을 추가해 넣을 수 있다.



HelloController.java

package com.example.sample.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

@RestController
@Api(value = "HelloController", description = "헬로 에이피아이")
public class HelloController {

	@RequestMapping(value="/hello", method= RequestMethod.GET)
	@ApiOperation(value="hello, World API", notes="hello, World를 반환하는 API, Ajax 통신 확인용.")
	public String helloWorld() {
		return "hello, World";
	}
}


SwaggerConfig.java

package com.example.sample.config;

import java.util.ArrayList;
import java.util.Collections;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMethod;

import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.ResponseMessage;
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 api() { 
        return new Docket(DocumentationType.SWAGGER_2)  
          .select()                                  
          .apis(RequestHandlerSelectors.basePackage("com.example.sample.controller") )              
          .paths(PathSelectors.any())
          .build()
          .apiInfo(apiInfo())
          .useDefaultResponseMessages(false)                                   
          .globalResponseMessage(RequestMethod.GET, getArrayList());
        
    }
    
    private ArrayList<ResponseMessage> getArrayList(){
    	ArrayList<ResponseMessage> lists = new ArrayList<ResponseMessage>();
    	
    	lists.add(new ResponseMessageBuilder().code(500).message("서버에러").responseModel(new ModelRef("Error")).build());
    	lists.add(new ResponseMessageBuilder().code(403).message("권한없음").responseModel(new ModelRef("Forbbiden")).build());
    	
    	return lists;
    }
    
    private ApiInfo apiInfo() {
        return new ApiInfo(
          "Hello REST API", 
          "Some custom description of API.", 
          "API TOS", 
          "Terms of service", 
          new Contact("야훔", "www.example.com", "myeaddress@company.com"), 
          "License of API", "API license URL", Collections.emptyList());
   }
}


코드가 좀 길어지긴 했는데 위와 같이 수정을 하고 서버를 재시작하면 아래와 같은 화면을 볼 수 있다.



이런식으로 Swagger를 적용시켜서 작업하면 나중에 API 문서를 따로 준비하느라 고생할 필요가 없겠지.


다음시간엔 처음에 이야기한 기능들을 위해 DB를 셋팅하고 QueryDSL을 설정하는 시간을 갖도록 하자.


오늘은 여기까지!

댓글
  • 프로필사진 lee http://localhost:8080/swagger-ui.html에 접속하면
    Unable to infer base url. This is common when using dynamic servlet registration or when the API is behind an API Gateway. The base url is the root of where all the swagger resources are served. For e.g. if the api is available at http://example.org/api/v2/api-docs then the base url is http://example.org/api/. Please enter the location manually:
    라는 알림이 뜨면서 안들어가집니다 이건 어떤 문제인가요?
    2018.06.28 15:25
  • 프로필사진 Favicon of https://blog.thereis.xyz 글쟁이 야훔 저도 처음보는 오류라서 해당 버그에 대해 알아보니 Spring Boot의 버전과 Swagger의 버전이 업데이트 됨에 따라 발생하는 오류인 것으로 짐작되네요.

    현재 이 문제로 여러 포럼에서 이야기를 하는 중인 것 같고 해당 문제에 대한 명확한 해결법은 조금 더 조사해봐야할 것 같습니다.

    제가 요즘 자바를 못하고 Django에 매달려 있는 상태라 자세한 답변이 어려운 점 이해해주세요 ㅠ
    2018.06.30 17:10 신고
댓글쓰기 폼