현재 API 명세 같은 경우 Notion을 통해 진행하고 있다.
API가 바뀔 때 마다 수정 작업을 해주고 있는데 상당히 귀찮다.....
이에 대한 부담을 줄여보고자 우리 프로젝트에 Swagger를 적용시켜봐야겠다는 생각이 들었다.
이번 포스팅은 Swagger가 무엇인지 알아보고 현재 프로젝트에 Swagger를 적용해보는 글을 쓰겠다.
위에 말했다시피 API 명세를 엑셀이나 Notion을 통해 작업을 하다보면 API가 바뀔 때 마다 수작업으로 변경을 해줘야 한다.. 이는 매우 귀찮기도 하고 개발자가 API 문서를 변경하는 것을 잊어서 문서에 나온 API 명세와 실제 API가 다른 경우가 있을 것이다.
이와 같이 API를 수작업으로 만들다보면 클라이언트 개발자와 서버 개발자 간의 비효율적인 커뮤니테이션이 이뤄지고, 문서에 대한 신뢰성이 문제가 된다.
이를 해결하기 위해서 Swagger나 Spring Docs와 같은 API 문서 자동화 라이브러리를 사용해볼 수 있다.
-> 나는 여기서 Swagger를 사용해보겠다.
서버로 요청되는 API 리스트를 HTML 화면으로 문서화하여 테스트할 수 있는 라이브러리
이 라이브러리는 서버가 가동되면서 @RestController를 읽어 API를 분석하여 HTML문서를 작성함
Spring에서 Swagger를 적용하기 위한 라이브러리로 Spring-Fox
와 Spring-Doc
이 있다.
먼저 Spring-Fox
같은 경우 오래전(2015)에 나온 라이브러리로 2020년 이후로 업데이트가 멈췄다고 한다. 그래서 Spring Boot 2.6이상 버전에서는 바로 적용이 안된다고 한다.
다음으로 Spring-Doc
은 최근(2019)에 나온 라이브러리로 업데이트가 최근까지 이뤄지고 있다. 또한 Spring boot 2.6 이상도 지원한다고 한다.
현재 진행하고 있는 프로젝트는 Spring Boot 3.0.5를 사용하고 있기 때문에 Spring-Doc을 사용하기로 했다.
💡 3.x.x 버전이 아니더라도 spring-doc을 사용하자
springdoc 라이브러리가 OpenAPI3.0 스펙에 맞는 JSON을 만들어주면, Swagger UI가 화면을 만들어서 JSON들을 띄워주는 역할을 한다.
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'
위와 같이 Swagger dependency를 추가하고
http://localhost:{해당 애플리케이션 포트}/swagger-ui/index.html에 접속하게 되면 아래와 같이 API 문서를 확인할 수 있다.
springdoc:
version: ${version}
api-docs:
path: /api-docs
default-consumes-media-type: application/json
default-produces-media-type: application/json
swagger-ui:
operations-sorter: alpha
tags-sorter: alpha
path: /swagger-ui.html
disable-swagger-default-url: true
display-query-params-without-oauth2: true
doc-expansion: none
paths-to-match:
- /api/**
- springdoc
- api-docs.path
- 기본값:
/v3/api-docs
- spring boot 웹 애플리케이션의 api를 OpenAPI3을 이용하여 json 형식화 한것의 경로
- default-consumes-media-type
- 기본값:
application/json
- request media type의 기본 값
- default-produces-media-type
- 기본값:
*/*
- response media type의 기본 값
- swagger-ui.operations-sorter
- 기본값: 컨트롤러 내에서 정의한 api 메서드 순
- 태그 내 각 api의 정렬 기준
- alpha: 알파벳 오름차순, method: http method 순
- swagger-ui.tags-sorter
- 태그 정렬 기준
- swagger-ui.path
- 기본 값:
/swagger-ui.html
- Swagger HTML 문서 경로
- swagger-ui.disable-swagger-default-url
- swagger-ui default url인 petstore html 문서 비활성화 여부
- v1.4.1 이상 버전부터 지원
- swagger-ui.display-query-params-without-oauth2
- 기본 값: false
- json화 된 config파일 대신 파라미터를 이용하여 swagger-ui에 접근하도록 한다.
- api-docs(
/api-docs
) 및 swagger-ui.configUrl(/api-docs/swagger-config
)를 두 번씩 호출하는 것을 방지한다.- swaggerui.doc-expansion
- 기본 값: list
- tag와 operation을 펼치는 방식에 대한 설정
- String=["list","full","none"]
- none으로 설정할 경우, tag 및 operation이 모두 닫힌채로 문서가 열린다.
- path-to-match
- OpenAPI 3으로 문서화할 api path 리스트
이렇게 다양한 설정 값들이 있는데, 나는 기본 설정으로 Swagger를 사용하겠다!
위의 설정 말고 더 많은 설정정보가 있는데, 해당 정보는 springdoc-openapi를 참고하면 된다.
OpenAPI의 Info 설정을 별도로 하지 않는 다면 아래와 같은 Swagger-ui가 자동으로 설정된다.
@Component
public class OpenApiConfig {
@Bean
public OpenAPI openAPI() {
Info info = new Info().title("user-service")
.description("user-service API");
return new OpenAPI()
.components(new Components())
.info(info);
}
}
위와 같이 info를 수정하면 아래와 같이 info가 변경됨을 볼 수 있다.
title, description말고도 version, termsOfService, contact, email, license, url 등 다른 정보들도 많이 추가할 수 있다!
아래 블로그에 아주 상세히 설명되어 있다.
💡 그 외 참고한 것들
[Spring Boot Tutorial] 15. Open API 3.0 + Swagger v3 상세설정
Spring swagger 3 사용방법(springdoc-openapi-ui)
UserController.java
@Tag(name = "유저관련 API")
@RestController
@RequiredArgsConstructor
@RequestMapping("/")
public class UserController {
private final Environment env;
private final UserService userService;
@GetMapping("/health_check")
public String status() {
return "hi";
}
@Operation(summary = "회원 정보 조회", description = "해당 user-id의 회원 정보 조회")
@GetMapping("/user/{user-id}")
public ResponseEntity<ResponseUserById> getUserById(@PathVariable("user-id") Long userId) {
return ResponseEntity.status(HttpStatus.OK).body(userService.getUserById(userId));
}
@Operation(summary = "회원 정보 수정", description = "해당 user-id의 회원 정보 수정")
@PutMapping("/user/{user-id}")
public ResponseEntity<Long> updateUser(@PathVariable("user-id") Long userId, @Valid @ModelAttribute RequestUpdateUser requestUpdateUser) {
return ResponseEntity.status(HttpStatus.OK).body(userService.updateUserById(userId, requestUpdateUser));
}
@Operation(summary = "회원 삭제", description = "해당 user-id의 회원 삭제")
@DeleteMapping("/user/{user-id}")
public ResponseEntity<Void> deleteUser(@PathVariable("user-id") Long userId) {
userService.deleteUser(userId);
return ResponseEntity.noContent().build();
}
}
ResponseUserById.java
@Schema(description = "사용자 정보(user-id) 응답")
@Getter
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseUserById {
@Schema(description = "유저 번호", example = "1")
private Long id;
@Schema(description = "로그인 아이디", example = "id1234")
private String loginId;
@Schema(description = "이름", example = "홍길동")
private String name;
@Schema(description = "휴대전화 번호")
private String phoneNumber;
@Schema(description = "생일")
private LocalDate birthday;
@Schema(description = "성별")
private Gender gender;
@Schema(description = "프로필 이미지 URL")
private String profileImage;
}
잘 적용됐음을 볼 수 있다!
이로써 프로젝트에 Swagger까지 적용시켜봤다!
근데 문제는 Swagger를 쓰려면 애플리케이션을 실행시켜놔야 한다는 것이다..😂
얼른 테스트를 마치고 클라우드에 배포할 수 있도록 해야겠다..!