API 문서 자동화 사용하는 이유?
Swagger UI API를 설정하고 문서 자동화 하는 이유는 내가 만든 API 인터페이스 문서를 잘 정리해서
다른 개발자들과 사용하는 모든 사람들에게 편의성을 제공하고
어떤 동작을 하는지에 대한 부분을 잘 표현하기 위함이라고 생각하면 됩니다.
최근에 사용했던 목적을 정리해보면
면접 과제용 API 개발하고 표현하기 위해서 많은 시간을 사용한것 같고
프로젝트 진행하면서 프론트앤드와 개발 진행하고 있는데 일정이 빠듯하다보니 Mock 데이터를 구성해서 API를 제공하는 목적으로
사용하면서 필요한부분 Swagger UI API를 표현하는 몇가지 유형 그리고 간단하게 API호출하는 테스트 코드까지 만들어 보려고 합니다.
Rest Doc을 많이 사용하나요? Swagger UI API를 많이 사용하나요?
이부분은 상황에 따라서 Rest Doc를 사용하기도 하고 Swagger UI를 사용하기도하는데 보통은
회사에서 자주빈도수 높게 사용하는것 위주로 진행됩니다.
코드에 스타일과 방법이 일관적인 방향이면 될것 같습니다. 현업에서도 둘다 사용하기 때문에 결국에는 두개다 사용하는 방법을 찾아보시고 알아두면 좋을것 같습니다.
Swagger UI 공식 사이트
공식 링크는 아래를 클릭하세요!!
문서 Documentation 그리고 샘플로 작성된 Swagger Site입니다.
다양한 유형들을 포함하고있어서 참고해서 구성하시면 좋을것 같습니다.
https://petstore.swagger.io/?_ga=2.21688507.1655130715.1661735233-383348530.1661735233
pet, store, user 는 Swagger UI로 만들어진 rest API 에대한 설명
아래 models 는 API만들면서 DTO에 해당하는 Request, Response 정의한 파라메타 필드들을 확인할수 있습니다.
Swagger UI 설정말고 Springdoc.org 로 시작해 보겠습니다.
swagger ui 사이트에서 제공하는 설정으로 진행할수있지만 springboot 이기때문에 Springdoc 를 이용해서 진행해보도록 하겠습니다.
내부적으로 swagger ui를 사용하는데 좀더 spring 레이어가 있고 webmvc, webflux 2가지 모두 지원하는 기능이라고 생각하면됩니다.
모로가던 Swagger UI API 인터페이스가 잘 나오기만 하면되는거라 한번 시작해보겠습니다.
https://springdoc.org/#Introduction
자세한 정보들은 사이트를 참고하시면됩니다.
OpenAPI3 Annotation 설명
AnnotationFieldDescription
@Tag | name | API 그룹(주로 컨트롤러 단위) 태그 이름 |
description | API 그룹(주로 컨트롤러 단위)에 대한 설명 | |
@Operation | summary | 메서드 동작에 대한 요약 |
description | 메서드 동작 설명 | |
tags | API 그룹 태그 이름 (생략가능) | |
responses | 메서드 Response 목록 | |
parameters | 메서드 Parameter 목록 | |
requestBody | 메서드 RequestBody | |
@ApiResponse | responseCode | HTTP 상태 코드 |
description | Response에 대한 설명 | |
content | Response 컨텐츠 유형 설정 - mediaType - schema : hedden(Schema 숨김 여부), implementation(Schema 대상 클래스) - examples : Response 예시 (@ExampleObject(value = "") 사용하여 작성) |
|
@Parameter | name | 파라미터 이름 |
description | 파라미터 설명 | |
required | 필수 여부 (true / false) | |
example | 예시 값 | |
@RequestBody | description | RequestBody에 대한 설명 |
@Schema | name | 모델 이름 |
description | 모델 / 필드에 대한 설명 | |
defaultValue | 기본 값 | |
required | 필수 여부 (true / false) | |
example | 예시 값 | |
@ParameterObject | - | Parameter Object의 필드를 Query Parameter로 추출 |
SpringDoc 로 시작하는 5분만에 만들어보는 Swagger UI API
Spring initializr 프로젝트만들기
Project : Gradle Project
Language : Java
Springboot : 2.7.3
Packaging : jar
java : 11
해당 정보로 프로젝트 생성하도록 하겠습니다. GENERATE 클릭!!
build.gradle
plugins {
id 'org.springframework.boot' version '2.7.3'
id 'io.spring.dependency-management' version '1.0.13.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
//implementation 'org.springframework.boot:spring-boot-starter-web'
// spring boot
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.boot:spring-boot-starter-tomcat'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'javax.validation:validation-api'
implementation ('org.springdoc:springdoc-openapi-ui:1.6.9') {
exclude group: 'org.springdoc', module: 'springdoc-openapi-webmvc-core'
}
implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.6.9'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
javadoc {
source = sourceSets.main.allJava
options.encoding = 'UTF-8'
}
tasks.named('test') {
useJUnitPlatform()
}
webflux 방식으로 처리하였습니다. web servlet 방식으로 하려면 메뉴랑 위에 주석처리한 web을 푸시고 webfulx를 변경하셔야합니다.
application.yml
server:
port: 8888
error:
include-message: always
include-binding-errors: always
include-stacktrace: never
include-exception: false
spring:
application:
name: demo-api-application
logging:
level:
org.springframework.boot.autoconfigure: info
springdoc:
swagger-ui:
path: /sample/swagger-ui.html
displayRequestDuration: true
operationsSorter: method
apisSorter: alpha
default-produces-media-type: application/json
기본 port 그리고 swagger ui 설정 정보입니다
OpenApiConfig 설정
@OpenAPIDefinition(info = @Info(
title = "샘플 OpenAPI Doc",
description = "샘플 대해 설명하는 문서입니다.",
version = "1.0"),
servers = @Server(url = "/", description = "Default server url"))
@Configuration
public class OpenApiConfig {
@Bean
public OpenApiCustomiser openApiCustomiser() {
return openApi -> openApi.getPaths().values().forEach(pathItem -> pathItem.readOperations().forEach(operation -> {
ApiResponses apiResponses = operation.getResponses();
if (!apiResponses.containsKey("404")) {
apiResponses.addApiResponse("404", new ApiResponse().description("Not Found"));
}
if (!apiResponses.containsKey("500")) {
apiResponses.addApiResponse("500", new ApiResponse().description("Server Error"));
}
}));
}
}
OpenAPiConfig 설정 Class입니다.
Controller 만들기 타입A
@RestController
@RequiredArgsConstructor
public class SampleTypeAController {
private final SampleService sampleService;
@Operation(
summary = "기능 단건 검색 TYPEA",
parameters = {
@Parameter(name = "index", description = "일련번호", example = "89821"),
},
description = "메뉴에 대한 설명을 기록해 주세요"
)
@GetMapping("/sample/typea/{index}")
public ResponseEntity<GenericCollectionResponse<SampleResponse>> getSample(@PathVariable long index){
return ResponseEntity.ok(sampleService.getSamples(
SampleRequest.builder()
.index(index)
.build()
));
}
}
Controller 만들기 타입B
소스코드와 Swagger UI용 Annotation 분리하기
@RestController
@RequiredArgsConstructor
public class SampleTypeBController implements SampleTypeBControllerApi {
private final SampleService sampleService;
public ResponseEntity<GenericCollectionResponse<SampleResponse>> getSample(@PathVariable long index){
return ResponseEntity.ok(sampleService.getSamples(
SampleRequest.builder()
.index(index)
.build()
));
}
}
꿀팁
Intellij 를 사용하신다면 controller 에서 interface 추출 팁
controller 선택 Refactor -> Extract interface 선택
Extract Interface 팝업에서 인터페이스 이름을 수정하고 "Member To Form interface" 에서 Member 선택후 Refactor 선택
하시면 작성했던 Controller에서도 Interface를 분리 할수 있습니다.
Controller > Refactor > Extract Interface 선택
Interface nam 변경, Members To Form Interface 에서 인터페이스 추출할 method선택
생성된 interface 를 볼수 있고 Implements 에 Swagger Annotation이 생성되었으니 기존에 Controller에 코드는 삭제하시면 됩니다.
@Tag(name = "대메뉴 > 하위메뉴B", description = "메뉴 기능을 제공합니다.")
public interface SampleTypeBControllerApi {
@Operation(
summary = "기능 단건 검색 TYPEB",
parameters = {
@Parameter(name = "index", description = "일련번호", example = "89821"),
},
description = "메뉴에 대한 설명을 기록해 주세요"
)
@GetMapping("/sample/typeb/{index}")
public ResponseEntity<GenericCollectionResponse<SampleResponse>> getSample(@PathVariable long index);
}
Swagger UI API 잘나오는지 클릭
application.yml 에 설정한 정보를 기반으로 아래 URI로 접근하시면됩니다.
http://localhost:8888/sample/swagger-ui.html
Swagger UI 표현하는방법으로 Controller 을 2가지 방법으로 표현하였습니다.
타입A 는 Controller.java에 swagger ui + code 포함한 내용입니다.
타입B 는 Controller.java Interface.java 2가지를 만들어서 Swagger UI와 Code를 분리하였습니다.
2가지모두 사용가능하기때문에 선호 하시는 방법으로 선택하시면 좋을것 같습니다.
GitHub 코드는 아래 공유 드립니다.
https://github.com/lswteen/swaggerdemo
즐거운 코딩 되세요!!
'Backend 개발자 > StackOverflow' 카테고리의 다른 글
MSSQL 맥북용 M1 추천 Tool Legacy 분석 Mssql 프로시저 검색하기 (1) | 2022.09.08 |
---|---|
Mac OS 맥북 Homebrew m1 설치 방법 (0) | 2022.08.30 |
Rest API 호출시 보일러 플레이트 코드를 리펙토링 하는 방법, 같은 모양의 양을 줄여보시오!! (0) | 2022.08.09 |
MSA 아키텍처 프로젝트 빅뱅 방식으로 God Object 처리시 발생하는 Tell Dont ask (0) | 2022.08.08 |
Springboot Rest API GetMapping 방식 @Setter 없이 @ParameterObject, @AllArgsConstructor 2가지로 @ModelAttribute 사용 하는 방법 (0) | 2022.06.23 |