Spring boot로 Swagger 적용하기
지난번에 했던건 그저 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", "[email protected]"),
"License of API", "API license URL", Collections.emptyList());
}
}
요런 화면이 나오고 우리가 만든 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", "[email protected]"),
"License of API", "API license URL", Collections.emptyList());
}
}
코드가 좀 길어지긴 했는데 위와 같이 수정을 하고 서버를 재시작하면 아래와 같은 화면을 볼 수 있다.
이런식으로 Swagger를 적용시켜서 작업하면 나중에 API 문서를 따로 준비하느라 고생할 필요가 없겠지.
다음시간엔 처음에 이야기한 기능들을 위해 DB를 셋팅하고 QueryDSL을 설정하는 시간을 갖도록 하자.
오늘은 여기까지!