Spring MVC API 문서화

이상수·2022년 7월 30일
0

TIL_Spring MVC

목록 보기
10/11
post-thumbnail
  1. 시작하게 된 계기 및 다짐 😮
  • 이번 코드스테이츠의 백엔드 엔지니어링 개발자 부트캠프에 참여하게 되면서 현직개발자 분들의 빠른 성장을 위한 조언 중 자신만의 블로그를 이용하여 배운 것 들을 정리하는게 많은 도움이 된다 하여 시작하게 되었다.

    • 그 날 배웠던 것을 길지 않아도 좋으니 정리하며 복습하는 습관 기르기
    • 주말에 다음주에 배울 내용들을 예습
    • 코딩 문제와 java코드들은 꾸준히 학습
    • 자료구조를 이용한 알고리즘 문제 해결 학습
  1. 학습 목표 😮
목표결과
API 문서화 이해O
Spring Rest Docs와 Swagger의 차이점 및 사용법 이해O
Spring Rest Docs를 위한 기본 설정 및 사용 방법을 이해O
Spring Rest Docs를 사용해서 API 문서를 생성 및 배포O
  1. 정리 😮

API 문서화


Ⅰ. @ 애너테이션

1. @ApiOperation(value=" ", notes =" ")




Ⅱ. API 문서화를 하는 이유


1. API 문서화

  • 클라이언트가 REST API 백엔드 애플리케이션 요청을 전송하기 위해서 알아야되는 요청정보를 문서로 정리해 놓은것
  • API 사용을 위한 정보를 담고있는 문서를 API문서 or API스펙 이라한다.
  • 개발자가 직접 API정보를 수기로 작성하거나 애플리케이션 빌드를 통해서 API자동 생성 가능


2. Spring Rest Docs vs Swagger

  • API문서 자동화 오픈소스

1). Swagger

  • @Apixxx 어노테이션을 Api문서를 자동생성하기 위해 굉장히 많이 필요하다.
  • Postman처럼 API요청 툴로써의 기능을 사용할 수 있다는 장점이 있다.

2). ★Spring Rest Docs의 API 문서화

  • Swagger와 달리 애플리케이션 문서 생성을 위한 애너테이션 같은 어떠한 정보도 추가되지 않음.
  • 테스트 케이스에서 전송하는 API문서 정보와 Controller에서 구현한 Request Body, Response Body, Query Parameter등의 정보가 하나라도 일치하지 않으면 실행결과가 failed가 되며 문서가 정상적으로 생기지 않음
  • API 스펙 정보와 API 문서 정보의 불일치로 인해 발생하는 문제를 방지

Extra

  1. Swagger
  1. SpringDoc




Spring Rest Docs


Ⅰ. Spring Rest Docs란

1. Spring Rest docs의 Api 문서 생성 흐름

1). 테스트 코드 작성

  • 슬라이스 테스트 코드 작성
  • API 스펙 정보 코드 작성(Request Body, Response Body, Query Parameter 등)


2). test 태스크(task) 실행

  • 작성된 슬라이스 테스트 코드 실행
  • 테스트 결과가 passed이면 다음진행, failed이면 다시 테스트 케이스 수정


3). API 문서 스니핏(.adoc 파일) 생성

  • passed로 넘어오면 테스트 코드에 포함된 API 스펙 정보 코드를 기반으로 API 문서 스니핏이 .adoc확장자를 가진 파일로 생성됨
    • 스니핏 : 코드의 일부 조각을 의미하는데, 문서의 일부조각으로 테스트 케이스 하나당 하나의 스니핏이 생성


4). API 문서 생성

  • 생성된 API 문서 스니핏을 모아 하나의 API 문서로 생성


5). API문서를 HTML로 변환

  • 생성된 API 문서를 HTML로 변환
  • HTML 변환된 뭄ㄴ서는 파일자체를 공유하거나 URL을 통해 해당 HTML에 접속하여 확인가능

2. Spring Rest docs 설정

0). Asciidoctor플러그인을 이용하여 Api 문서를 생성

1). build.gradle 설정

2). API 문서 스니핏을 사용하기 위한 템플릿 API 문서 생성

3). 스니핏을 사용해 최종 API 문서로 만들어주는 템플릿 문서를 생성

[예제 Code]

plugins {
	id 'org.springframework.boot' version '2.7.1'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id "org.asciidoctor.jvm.convert" version "3.3.2"    // (1)
	id 'java'
}

group = 'com.codestates'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
	mavenCentral()
}

// (2)
ext {
	set('snippetsDir', file("build/generated-snippets"))
}

// (3)
configurations {
	asciidoctorExtensions
}

dependencies {
       // (4)
	testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
  
  // (5) 
	asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor'

	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-validation'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'com.h2database:h2'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	implementation 'org.mapstruct:mapstruct:1.5.1.Final'
	annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.1.Final'
	implementation 'org.springframework.boot:spring-boot-starter-mail'

	implementation 'com.google.code.gson:gson'
}

// (6)
tasks.named('test') {
	outputs.dir snippetsDir
	useJUnitPlatform()
}

// (7)
tasks.named('asciidoctor') {
	configurations "asciidoctorExtensions"
	inputs.dir snippetsDir
	dependsOn test
}

// (8)
task copyDocument(type: Copy) {
	dependsOn asciidoctor            // (8-1)
	from file("${asciidoctor.outputDir}")   // (8-2)
	into file("src/main/resources/static/docs")   // (8-3)
}

build {
	dependsOn copyDocument  // (9)
}

// (10)
bootJar {
	dependsOn copyDocument    // (10-1)
	from ("${asciidoctor.outputDir}") {  // (10-2)
		into 'static/docs'     // (10-3)
	}
}
(1)에서는 .adoc 파일 확장자를 가지는 AsciiDoc 문서를 생성해주는 Asciidoctor를 사용하기 위한 플러그인을 추가합니다.

(2)에서는 ext 변수의 set() 메서드를 이용해서 API 문서 스니핏이 생성될 경로를 지정합니다.

(3)에서는 AsciiDoctor에서 사용되는 의존 그룹을 지정하고 있습니다. :asciidoctor task가 실행되면 내부적으로 (3)에서 지정한 ‘asciidoctorExtensions’라는 그룹을 지정합니다.

(4)에서 'org.springframework.restdocs:spring-restdocs-mockmvc'를 추가함으로써 spring-restdocs-core와 spring-restdocs-mockmvc 의존 라이브러리가 추가됩니다.

(5)에서 spring-restdocs-asciidoctor 의존 라이브러리를 추가합니다. (3)에서 지정한 asciidoctorExtensions 그룹에 의존 라이브러리가 포함이 됩니다.

(6)에서는 :test task 실행 시, API 문서 생성 스니핏 디렉토리 경로를 설정합니다.

(7)에서는 :asciidoctor task 실행 시, Asciidoctor 기능을 사용하기 위해 :asciidoctor task에 asciidoctorExtensions 을 설정합니다.

(8)은 :build task 실행 전에 실행되는 task입니다. :copyDocument task가 수행되면 index.html 파일이 src/main/resources/static/docs 에 copy 되며, copy된 index.html 파일은 API 문서를 파일 형태로 외부에 제공하기 위한 용도로 사용할 수 있습니다.

(8-1)에서는 :asciidoctor task가 실행된 후에 task가 실행 되도록 의존성을 설정합니다.

(8-2)에서는 "build/docs/asciidoc/" 경로에 생성되는 index.html을 copy한 후,

(8-3)의 "src/main/resources/static/docs" 경로로 index.html을 추가해 줍니다.

(9)에서는 :build task가 실행되기 전에 :copyDocument task가 먼저 수행 되도록 합니다.

(10)에서는 애플리케이션 실행 파일이 생성하는 :bootJar task 설정입니다.

(10-1)에서는 :bootJar task 실행 전에 :copyDocument task가 실행 되도록 의존성을 설정합니다.

(10-2)에서는 Asciidoctor 실행으로 생성되는 index.html 파일을 jar 파일 안에 추가해 줍니다.
jar 파일에 index.html을 추가해 줌으로써 웹 브라우저에서 접속(http://localhost:8080/docs/index.html) 후, API 문서를 확인할 수 있습니다.



Extra

  1. Gradle
  1. ext 변수

Ⅲ. Controller 테스트 케이스에 Spring RestDocs 적용

1. 애너테이션

  1. @WebMvcTest(MemberController.class)

    • @SpringBootTest 애너테이션 대신 사용한 애너테이션으로, Controller 테스트를 하기 위한 전용 애너테이션이다
    • 괄호안의 Controller 클래스를 테스트해줌
  2. @MockBean(JpaMetamodelMappingContext.class)

    • JPA에서 사용하는 Bean들을 Mock객체로 주입해주는 설정
    • SPring boot 기반의 테스트는 항상 최상위 패키지 경로에 있는 xxxxxxApplication 클래스를 찾아서 생성
    • Main에 @EnableJpaAuditing 애너테이션이 추가 , @WebMvcTest사용시 관련된 Bean들을 필요로 하여
      jpaMetaModelMappingContext를 Mock객체로 주입해주어야 한다.
  3. @AutoConfigureRestDocs

    • RestDocs에 대한 자동구성을 위함



2. API 문서 생성을 위한 슬라이스 테스트 작성

  1. .andDo(document())

    • document(...) : API 문서를 생성하기 위한 RestDocs의 메서드
    • andDo(...) : andExpect처럼 검증하는 것이 아니라 일반적인 동작 정의
  2. document(...)

    • API스펙 정보를 받아 실질적인 문서화 작업을 수행하는 RestDocumentationResultHandler클래스 핵심 메서드

    1). 첫 파라미터

    • "post-member"로 지정하면, 문서 스니핏은 post-member 디렉토리 하위에 생성
    • getRequestPreProcessor(), getResponsePreProcessor() 문서 스니핏 생성전 request와 response에 해당하는 문서 영역을 전처리하는 역할을 한다.
    • 위 두 메서드는 인터페이스로 공통화한 후 모든 테스트 케이스에서 사용할 수 있도록

    2). preprocessRequest(prettyPrint())/preprocessResponse(prettyPrint())

    • 문서에 표시되는 JSON 포맷의 request/response body를 예쁘게 표현해줌

    3). requestFileds(...)

    • 문서로 표현될 request body의미 파라미터로 전달되는 List의 원소인 FieldDescriptor 객체가 request body에 포함된 데이터를 표현한다.
      [Ex. fieldWithPath("memberId").type(JsonFieldType.NUMBER).description("회원 식별자").ignored()]
      위 코드는 request body를 JSON 포맷으로 표현 했을 때 하나의 프로퍼티를 의미하는 fieldDescriptor이다.
      type(JsonFieldType.STRING)은 JSON 프로퍼티의 값이 문자열임을 의미

    4). reponseFields(...)

    • 위와 같지만 response body를 의미한다.

    5). ignore()

    • memberId의 경우 path variable 정보로 전달받아 request body에 매핑되지 않아 API 스펙 정보에서 제외

    6). optional()

    • 선택적으로 수정할 수 있게 만들기 위하여 request body에 optional()을 추가

    7). pathParameters(....)

    • URL의 path variable 정보를 추가하기 위함으로써, 사용
      [Ex. pathParameters(parameterWithName("member-id").description("회원 식별자"))]



Extra

  1. 인터페이스

    1) default 메서드

    • interface에서도 메소드 구현이 가능하다.
    • 오버라이딩 가능 , (implement)
    • 참조 변수로 함수를 호출할 수 있다.

    2). static 메서드

    • interface에서도 메소드 구현이 가능하다.
    • 반드시 클래스 명으로 메소드를 호출해야 한다.
    • 재정의는 불가능
  2. Spring Rest Docs

  1. API 문서화 작업 RestDocumentationResultHandler 의 document(…)의 파라미터
  1. JSON Field Types의 종류

Ⅲ. 스니핏을 이용한 API 문서화

1. API 문서 템플릿 생성을 위한 디렉토리 및 문서 생성

  1. API 문서 스니핏을 이용하여 제대로된 문서를 만들기 위해서 스니핏을 포함하는 템플릿 문서가 필요

    • Gradle 프로젝트의 경우, 템플릿 문서가 위치하는 디폴트 경로가 “src/docs/asciidoc"
    • 이 디폴트 경로안에 index.adoc 템플릿 파일 생성
  2. 템플릿 문서 내용 추가

    • index.adoc에 Asciidoc 문법으로 템플릿 문서 작성
    • ’include::{snippets}/스니핏 문서가 위치한 디렉토리/스니핏 문서파일명.adoc[]’ 의 형태로 스니핏을 사용한다.
    • src/main/resources/static/docs/ 디렉토리에 위치됨
    • http://localhost:8080/docs/index.html 주소



Extra

  1. 템플릿 문서와 문서 스니핏을 이용해 API 문서를 생성

==========================================================

Ⅳ. Spring Rest Docs에서의 Asciidoc

1. Asciidoc

  • Spring Rest Docs를 통해 생성되는 텍스트 기반 문서 포맷
  • 기술 문서 작성을 위해 설계된 가벼운 마크업 언어

1). 목차구성

[예제Code]

= 커피 주문 애플리케이션     // (1)
:sectnums:                  // (2)
:toc: left                  // (3)
:toclevels: 4               // (4)
:toc-title: Table of Contents   // (5)
:source-highlighter: prettify   // (6)

(1) 문서의 제목을 작성하기 위해서는 =를 추가 (====와 같이 =의 개수가 늘어날 수록 글자는 작아짐)
(2) 목차에서 각 섹션에 넘버링을 해주기 위해 :sectnums: 를 추가
(3) :toc: 는 목차를 문서의 어느 위치에 구성할 것인지를 설정 (왼쪽에 목차가 표시되도록 left)
(4) :toclevels: 은 목차에 표시할 제목의 level을 지정 . (level의 수만큼 ==== 포함지정)
(5) :toc-title: 은 목차의 제목을 지정
(6) :source-highlighter: 문서에 표시되는 소스 코드 하일라이터를 지정
(7) *** 를 추가하면 문단을 나눠주는 수평선이 추가됨
(8) NOTE:, TIP:, IMPORTANT:, WARNING: 과 같이 문구 추가가능


2). 문서 스니핏을 템플릿 문서에 포함

[예제 Code]

== MemberController
=== 회원 등록
.curl-request       // (1)
include::{snippets}/post-member/http-request.adoc[]    // (2)

.request-fields
include::{snippets}/post-member/request-fields.adoc[]

.http-response
include::{snippets}/post-member/http-response.adoc[]
...

(1) .curl-request의 .은 하나의 스니핏 섹션 제목을 표현하고, curl-request는 섹션의 제목이다(직접지정).
(2) include는 Asciidoctor의 매크로 중 하나고 ::를 통하여 사용,
{sinippets}는 해당 스니핏이 생성되는 default경로를 의미하며 build.gradle에서 설정한 sinppertsDir를 참조


3). URL Scheme 자동인식

  • http, http, ftp, irc, mailto, hgd@gmail.com 를 자동으로 인식하여 링크가 설정됨
  • image:: link를 이용하여 이미지를 추가할 수 있음



2. Asciidortor란

  • AskciiDoc포맷의 문서를 파싱해서 PDF,HTML5 등의 문서를 생성하는 툴
  • Askciidoc포맷의 문서를 HTML 파일로 변경하기 위해 내부적으로 Asciidoctor를 사용한다.



  1. 피드백 😮
  • Spring 에서 Rest Docs를 이용하여 문서화를 작업하는 과정을 학습하였다.

  • Swagger의 경우, 코드 @Apixxx 처럼 어노테이션을 활용하여 코드에 작성하는 방법이지만, 보기가 어렵고 복잡하여 잘 사용하지 않는다.

    *Rest Docs의 경우, 각 Controller의 테스트 케이스에 대하여 request body와 response body를 이용하여 작성하고, Asciidoc라이브러리를 이용하여 작성한다.

  1. 앞으로 해야 될 것 😮
  • 매일 꾸준히 할 것
    • 꾸준히 velog 작성
    • Java 언어 및 Algorithm 공부(Coding-Test)
    • 틈틈히 운동 하기

  • 내일 해야 할 것
    • Spring applcation 빌드/배포
profile
Will be great Backend-developer

0개의 댓글