Spring - REST API 문서화

Seongjin Jo·2023년 1월 5일
0

REST API

목록 보기
4/4

💥 SPRING REST DOCS

--

API 문서화 이유

우선, 우리는 백엔드 개발을 주도적으로 하는 입장이다. 하나의 웹,앱 애플리케이션이 만들어지려면 서버와 클라이언트 두 부분에서의 개발이 완료 되어야 한다. 그리고 이 둘은 API를 이용해서 서로 정보를 주고 받는다. 근데 여기서, 이 백엔드 서버 개발자가 개발한 API를 어떻게 사용하는지, 무엇인지, 등등 클라이언트 개발자가 직접 개발한 것이 아니기 때문에 알수가 없다. 그렇기 때문에 개발된 API 관련해서 문서화 시켜서 클라이언트 개발자가 알수있게 만들어서 줘야한다. 이것을 문서화라고 한다.
나는 REST DOCS 라는 스프링에서 제공하는 문서화 기능을 사용할 것이다.

장점

  • 운영 코드에 영향이 없다
  • Test 케이스 실행 -> 문서를 자동으로 생성해준다.
  • API 문서 생성 -> Client에게 문서화해서 전달

사용 방법

1.gradle 설정

https://spring.io/projects/spring-restdocs#learn 의 참조 문서를 들어가 보면 친절하게 알려준다.

buildscript {
	ext {
		queryDslVersion = "5.0.0"
	}
}

plugins {
	id 'java'
	id 'org.springframework.boot' version '2.7.7'
	//querydsl 추가
	id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
	id "org.asciidoctor.jvm.convert" version "3.3.2"
}

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

configurations {
	asciidoctorExt
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

ext{
	snippetsDir = file('build/generated-snippets')
	asciidocVersion = "2.0.6.RELEASE"
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-validation'
	implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
	annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}"

	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'

	runtimeOnly 'com.mysql:mysql-connector-j'

	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	//REST DOCS
	asciidoctorExt "org.springframework.restdocs:spring-restdocs-asciidoctor:${asciidocVersion}"
	testImplementation "org.springframework.restdocs:spring-restdocs-mockmvc:${asciidocVersion}"
}

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

asciidoctor {
	inputs.dir snippetsDir
	configurations 'asciidoctorExt'
	dependsOn test
}

//querydsl 추가 시작
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
	jpa = true
	querydslSourcesDir = querydslDir
}
sourceSets {
	main.java.srcDir querydslDir
}
configurations {
	querydsl.extendsFrom compileClasspath}
compileQuerydsl {
	options.annotationProcessorPath = configurations.querydsl
}
//querydsl 추가 끝

bootJar {
	dependsOn asciidoctor
	copy{
		from asciidoctor.outputDir
		into "src/main/resources/static/docs"
	}
}

2.REST DOCS용 Test를 만든다

ControllerDocsTest를 만든다

@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.hodolman.com", uriPort = 443)
@ExtendWith(RestDocumentationExtension.class)
public class PostControllerDocTest {

    @Autowired
    private MockMvc mockMvc;
    @Autowired
    private PostRepository postRepository;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    @DisplayName("글 단건 조회")
    void test1() throws Exception {

        //given
        Post post = Post.builder()
                .title("제목")
                .content("내용")
                .build();
        postRepository.save(post);
        //expected
        mockMvc.perform(RestDocumentationRequestBuilders.get("/posts/{postId}",post.getId())
                        .accept(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
                .andDo(document("post-inquiry",pathParameters(
                        parameterWithName("postId").description("게시글 ID")
                    ),
                        responseFields(
                                fieldWithPath("id").description("게시글 ID"),
                                fieldWithPath("title").description("제목"),
                                fieldWithPath("content").description("내용")
                        )
                ));
    }

    @Test
    @DisplayName("글 등록")
    void test2() throws Exception {
        //given
        PostCreate request = PostCreate.builder()
                .title("제목")
                .content("내용 입니다.")
                .build();

        String json = objectMapper.writeValueAsString(request);

        //expected
        mockMvc.perform(RestDocumentationRequestBuilders.post("/posts")
                        .contentType(MediaType.APPLICATION_JSON)
                        .accept(MediaType.APPLICATION_JSON)
                        .content(json))
                .andDo(print())
                .andExpect(status().isOk())
                .andDo(document("post-create",
                        requestFields(
                                fieldWithPath("title").description("제목").attributes(key("constraint").value("좋은제목 입력해주세요.")),
                                fieldWithPath("content").description("내용").optional()
                        )
                ));
    }


}

1.우리는 우선 스프링 컨테이너의 정보를 가져와 테스트를 할것이기 때문에 @SpringbootTest를 붙여준다.
2.@AutoConfigureMockMvc 를 붙여서 MockMvc를 주입받는다.
3.@AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.hodolman.com", uriPort = 443) 를 붙이면 직접 API문서에 나오는 주소를 설정할수있다.
4.@ExtendWith(RestDocumentationExtension.class) 를 설정하면 build/generated-snippets 이 경로에 Test한 API response,request등등 의 정보가 담긴다.

3.MockMvc를 이용한 Test 진행

RestDocs는 MockMvc를 이용한 Test의 정보를 가지고 API를 문서화 한다.
위의 코드에서 이 두가지를 API 문서화 해보았다.

  1. 글 조회 API
  2. 글 등록 API

.andDo() 메서드에서 document("제목","파라미터 정보") 를 이용.
build/generated-snippets 경로에 파일 생성 후 저장된다.
1.pathParameters() 정보
2.responseFields() 정보
3.requestFields() 정보
를 담아서 문서화 할 수 있다.

4.빌드

1.우측 gradle documentation에 있는 asciidoctor를 실행하면 testCode가 돌아가면서 build파일에 snippets정보가 초기화 된다.

2.gradle -> build,bootJar를 실행하면 build.gradle에 설정했던
bootJar {
dependsOn asciidoctor
copy{
from asciidoctor.outputDir
into "src/main/resources/static/docs"
}
}
gradle 설정에 의해서 static/docs경로에 asciidoc 파일이 생성되고 index.adoc파일이 생성된다. build,bootjar를 실행 할 때마다, 갱신된다.

3.그 후에 서버를 종료했다가 다시 빌드하면 API 문서가 있는 것을 확인 할 수 있다. 갱신도 같은 방법이다.

5.문서 커스텀

test/resources/org.springframework.restdocs.templates.asciidoctor 를 만들면 request-fields.snippet 이라는 파일이 생성되는데 이 파일을 수정하면 원하는 대로 커스텀 할 수 있다.
이 문서는 mustache 언어를 사용한다.

결과


0개의 댓글