Spring API Documentation
- REST API 문서 자동화에 대한 정리
- SpringDoc OpenApi+swagger 와 Spring Rest Docs 정리
Springfox Swagger와 Springdoc OpenAPI 3.0
- Swagger
- RESTful Web Service를 만들 때 API의 문서를 자동으로 만들어 주고, API를 직접 테스트해 볼 수 있는 UI 툴을 제공
- Springfox Swagger
- Swagger를 이용해 API 문서를 쉽게 쓸수있도록 도와주는 라이브러리로 Springfox가 있다.
- Springdoc
- Springfox는 2018년 6월을 마지막으로 업데이트가 중단되었는 데(2년 후 다시 업데이트) 이 때 Springdoc이 나타남
- Springdoc도 Springfox와 마찬가지로 swagger 문서를 쉽게 작성할 수 있도록 도와주는 라이브러리
- 이미지 출처: https://oingdaddy.tistory.com/271?category=824422
Springdoc OpenAPI 3.0
- dependency
// https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.4'
- 설정(application.yml)
springdoc: version: '@project.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 web application의 api를 OpenAPI 3.0을 이용하여 JSON 형식화한 것의 경로
- springdoc.default-consumes-media-type
- 기본값 : application/json
- request media type 의 기본 값
- springdoc.default-produces-media-type
- 기본값 : /
- response media type 의 기본 값
- springdoc.swagger-ui.operations-sorter
- 기본값 : 컨트롤러 내에서 정의한 api 메서드 순
- 태그 내 각 api의 정렬 기준
- alpha(알파벳 오름차순), method(http method 순)
- springdoc.swagger-ui.tags-sorter
- 태그 정렬 기준
- springdoc.swagger-ui.path
- 기본 값 : /swagger-ui.html
- Swagger HTML 문서 경로
- springdoc.swagger-ui.disable-swagger-default-url
- swagger-ui default url인 petstore html 문서 비활성화 여부
- v1.4.1 이상 버전부터 지원
- springdoc.swagger-ui.display-query-params-without-oauth2
- 기본 값 : false
- json화 된 config파일 대신 파라미터를 이용하여 swagger-ui에 접근하도록 한다
- api-docs(/api-docs) 및 swagger-ui.configUrl(/api-docs/swagger-config)를 두번씩 호출 방지
- v1.4.1 이상 버전부터 지원
- springdoc.swaggerui.doc-expansion
- 기본 값: list
- tag와 operation을 펼치는 방식에 대한 설정
- [“list”, “full”, “none”]
- none으로 설정할 경우, tag 및 operation이 모두 닫힌채로 문서가 열립니다.
- springdoc.paths-to-match
- OpenAPI 3 로 문서화할 api path 리스트
- springdoc.api-docs.path
- sample controller
@GetMapping("/api/accounts/{accountId}") public ResponseEntity<AccountResponse> getAccountByAccountId(@PathVariable String accountId) { return ResponseEntity.ok(accountService.findAccountByAccountId(accountId)); } @PostMapping("/api/accounts") public ResponseEntity<AccountResponse> saveAccount(@RequestBody AccountResource accountResource) { return ResponseEntity.status(HttpStatus.CREATED) .body(accountService.saveAccount(accountResource)); } @PutMapping("/api/accounts/{accountId}") public ResponseEntity<AccountResponse> updateAccount(@PathVariable String accountId, @RequestBody AccountResource accountResource) { return ResponseEntity.ok(accountService.updateAccount(accountId, accountResource)); }
- document 접속
- http://localhost:{port}/api-docs
{ "openapi":"3.0.1", "info":{ "title":"OpenAPI definition", "version":"v0" }, "servers":[ { "url":"http://localhost:8000", "description":"Generated server url" } ], "paths": { "/api/accounts/{accountId}":{ "get":{ "tags":["account-controller"], "operationId":"getAccountByAccountId", "parameters":[ { "name":"accountId", "in":"path", "required":true, "schema":{ "type":"string" } } ], "responses":{ "200":{ "description":"OK", "content":{ "application/json":{ "schema":{ "$ref":"#/components/schemas/AccountResponse" }}}}}}, ... } } "components":{ "schemas":{ "AccountResource":{ "type":"object", "properties":{ "name":{ "type":"string" }, ... } }
- 화면에 뿌려지기 위한 원본 데이터를 가지고 오는것을 확인할 수 있다.
-
http://localhost:{port}/swagger-ui.html
- /api-docs에서 가지고 온 데이터를 swagger-ui 화면에 뿌려준다.
- 내가 지정한 path에 대한 정보를 확인할 수 있다.
- http://localhost:{port}/api-docs
-
Annotation |swagger 3 annotations|swagger 2 annotations|description| |—|—|—| |@Tag|@Api|클래스를 Swagger 리소스로 표시| |@Parameter(hidden = true) or @Operation(hidden = true) or @Hidden|@ApiIgnore| API 작업에서 단일 매개 변수를 나타냄| |@Parameter|@ApiImplicitParam|API 작업에서 단일 매개 변수를 나타냄| |@Parameters|@ApiImplicitParams|API 작업에서 복수 매개 변수를 나타냄| |@Schema|@ApiModel|Swagger 모델에 대한 추가 정보를 제공| |@Schema(accessMode = READ_ONLY)|@ApiModelProperty(hidden = true)|모델 속성의 데이터를 추가하고 조작| |@Schema|@ApiModelProperty|Swagger 모델에 대한 추가 정보를 제공| |@Operation(summary = “foo”, description = “bar”)|@ApiOperation(value = “foo”, notes = “bar”)|특정 경로에 대한 작업 또는 일반적으로 HTTP 메서드를 설명| |@Parameter|@ApiParam|작업 매개 변수에 대한 추가 메타 데이터를 추가| |@ApiResponse(responseCode = “404”, description = “foo”)|@ApiResponse(code = 404, message = “foo”)|작업의 가능한 응답을 설명|
- 적용 예
@RestController @RequestMapping("/api") @Tag(name = "Account controller", description = "Account controller desc") public class AccountController { private final AccountService accountService; @Autowired public AccountController(AccountService accountService) { this.accountService = accountService; } @Operation( summary = "사용자 정보 조회" , description = "사용자의 ID를 통해 사용자의 정보를 조회한다." , tags = { "contact" }) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "successful operation", content = @Content(array = @ArraySchema(schema = @Schema(implementation = Contact.class)))) }) @GetMapping("/accounts/{accountId}") public ResponseEntity<AccountResponse> getAccountByAccountId(@PathVariable String accountId) { return ResponseEntity.ok(accountService.findAccountByAccountId(accountId)); }
- 적용 예
Spring REST Docs
- Swagger와 차이점
- 테스트가 성공해야 문서가 작성 된다.
- REST Docs로 문서를 작성하는 것은 API의 신뢰도를 높이고 테스트 코드의 검증을 강제로 하게 만든다
- 실제 코드에 추가되는 코드가 없다.
- 프로덕션 코드와 분리되어 있기 때문에 Swagger같이 Config 설정 코드나 어노테이션이 프로덕션 코드를 더럽히지 않는다.
- 테스트가 성공해야 문서가 작성 된다.
- dependency 추가
plugins { id "org.asciidoctor.convert" version "1.5.9.2" } dependencies { asciidoctor 'org.springframework.restdocs:spring-restdocs-asciidoctor' testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' } ext { snippetsDir = file('build/generated-snippets') } test { outputs.dir snippetsDir } asciidoctor { inputs.dir snippetsDir dependsOn test } // JAR 파일에 패키징하는 설정 bootJar { dependsOn asciidoctor from ("${asciidoctor.outputDir}/html5") { into 'static/docs' } }
- 테스트 코드 작성
@AutoConfigureMockMvc @AutoConfigureRestDocs @SpringBootTest class AccountControllerTest { @Autowired MockMvc mockMvc; @MockBean AccountService accountService; @Autowired ObjectMapper objectMapper; @Test void saveAccountTest() throws Exception { final AccountResponse accountResponse = new AccountResponse("TEST", "1234", LocalDateTime.of(2022, 5, 10, 22, 00)); final AccountResource accountResource = new AccountResource("TEST", "TEST1234"); when(accountService.saveAccount(any())).thenReturn(accountResponse); this.mockMvc.perform(post("/api/accounts") .content(objectMapper.writeValueAsString(accountResource)) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()) // 4 .andDo(MockMvcRestDocumentation.document("account-create", PayloadDocumentation.requestFields( PayloadDocumentation.fieldWithPath("name").description("Account Name").optional(), PayloadDocumentation.fieldWithPath("password").description("AccountPassword") ), PayloadDocumentation.responseFields( PayloadDocumentation.fieldWithPath("name").description("Account Save Name"), PayloadDocumentation.fieldWithPath("accountId").description("Account Id"), PayloadDocumentation.fieldWithPath("createdAt").description("Account created time") ) )); } }
- @AutoConfigureRestDocs
- Spring REST Docs에 대해 auto-configuration 할 수 있도록 class 파일에 적용하는 어노테이션
- Test 코드
- mockMvc를 통해 API를 호출한 후, andDo에 다큐먼트를 작성한다.
- MockMvcRestDocumentation.document
- parameter1: document 이름
- parameter2: request 설명
- parameter3: response 설명
- fieldWithPath는 key 값 description는 fieldWithPath 설명
- @AutoConfigureRestDocs
-
문서화
- 테스트 코드를 작성한 후 빌드하면 문서가 생성되는 것을 확인할 수 있다.
- /src/docs/asciidoc 폴더를 생성하고, *.adoc 파일을 생성하자
= Spring REST Docs :toc: left :toclevels: 2 :sectlinks: [[resources-account]] == Account [[resources-account-create]] === Account 생성 ==== HTTP request include::{snippets}/account-create/http-request.adoc[] ==== HTTP response include::{snippets}/account-create/http-response.adoc[]
- Asciidoctor는 일반 텍스트를 처리하고 필요에 맞게 스타일 및 레이아웃 된 HTML을 생성한다.
- 작성 후 빌드 하면 build/asciidoc/html5와 src/main/resources/static/docs에 html 파일 생성된 것을 확인할 수 있다
- http://localhost:8080/docs/api-docs.html 를 접속하면 문서를 확인할 수 있다
참고
- Springfox와 Springdoc: https://junho85.pe.kr/1583
- https://oingdaddy.tistory.com/271?category=824422
- https://oingdaddy.tistory.com/272?category=824422
- Springdoc 설정: https://blog.jiniworld.me/83 [hello jiniworld]
- https://tecoble.techcourse.co.kr/post/2020-08-18-spring-rest-docs/