우테코/요즘카페

RestDocs + OAS 도입기 (feat. RestAssured)

dev_kong 2023. 9. 1. 13:28
728x90
728x90

1. API 문서 자동화의 이유

프로젝트를 진행하면서, 이전까지는 Notion을 이용해 API docs 를 작성하고 관리하였다.
하지만 당연하게도 기능개발을 하면서 몇몇 이유로 API docs를 수정해야 하는 일이 생겼다.


그때마다 노션에 들어가서 API docs를 변경하는 것은 여간 번거로운 일이 아니었다.

심지어 어떤 때는 기능개발에 정신이 팔려 API docs의 업데이트를 새까맣게 까먹고 있다가,
프론트에서 변경 전 API 주소로 요청을 하는 경우도 있었다.

 

해야된다는 것은 문제가 터지기 전부터 인지하고 있었으나, 기능 개발이 우선 이란 마음에 차일피일 미루다,
더 이상은 미룰 수 없다! 라는 마음으로 API 문서 자동화를 진행하기로 했다.

2. RestDocs vs Swagger 그리고 OAS

이 부분은 팀원 모두가 한마음으로 RestDocs를 외쳤다.
나를 포함해 기존에 Swagger를 사용해본 경험이 있는 크루들이 프로덕션 코드에 문서화를 위한 코드가 포함되는것을 아주아주 마음에 안들어했다.

 

또한 RestDocs의 경우 테스트 코드가 성공해야 문서 작성이 가능하므로,
문서의 신뢰성이 높아진다.

 

물론 테스트 코드 작성 시에 내부 구현을 싹다 Mocking 해버린다면
이거 믿어도 되는건가... 싶은 문서가 생겨나긴 하지만,
우리 팀은 이번 프로젝트에서 Mocking 을 사용한 테스트를 최대한 배제 하기로 하였기에
신뢰도 높은 문서가 생성될 것이라 생각했다.

 

하지만 Swagger를 선택하지 않음으로 인한 놓치게 되는 아쉬운 부분도 분명이 존재했다.
RestDocs로 api 문서화를 하게되면, adoc을 통해 html 파일을 만들어주는데..
이렇게 만들어진 문서는 아름답지 못하다..


한 마디로 UI가 구리다.
또한 Swagger로 만들어진 문서에선 API Test 기능이 지원 되지만, RestDocs는 그렇지 않다.

 

  장점 단점
RestDocs 테스트코드 기반 -> 신뢰성 높음 구린 UI
  프로덕션 코드 영향 X 문서에서 API Test 미지원
Swagger UI가 예쁘다! 프로덕션 코드가 지저분해진다.
  문서에서 API Test 지원  

 

나를 포함해서 욕심쟁이들로 이뤄진 우리팀은 두마리 토끼를 잡기 위해
RestDocs를 통해 만들어진 adoc 파일을 OAS 파일로 API spec을 시각화 해주기로 했다.

 

Swagger는 OAS 파일을 해석하여 API Spec을 시각화 한다.

우리 팀은 Swagger 보다 더 이쁜 문서 양식을 발견하여,
결론적으로는 Swagger를 통해 시각화 하지는 않았지만,
이 양식 역시 OAS 파일을 해석하여 API spec을 시각화 한다.

2-1. restdocs-api-spec

문제는 RestDocs 가 만들어 준 adoc 파일을 어떻게 OAS 파일로 변환하냐는 것인데,
매우 고맙게도 OAS파일을 만들어 주는 오픈소스(restdocs-api-spec) 가 있다.

 

물론 직접 java를 이용해 파일을 변환해줄 수도 있겠지만...
그렇게 된다면 배보다 배꼽이 더 큰 상황이 되버리니 잘 만들어둔 오픈 소스를 사용하자!

 

3. 적용

3-1. RestDocs

정하는게 어렵지 사용은 어렵지 않다.
RestDocs는 공식문서가 굉장히 잘돼있다.

 

plugins { 
    id "org.asciidoctor.jvm.convert" version "3.3.2"
}

configurations {
    asciidoctorExt 
}

dependencies {
    asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor:{project-version}' 
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc:{project-version}' 
}

ext { 
    snippetsDir = file('build/generated-snippets')
}

test { 
    outputs.dir snippetsDir
}

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


이게 공식문서에 나와있는 의존성추가 부분인데 여기서 우리가 필요한 것만 골라쓰면 된다.
asciidoctor는 adoc 파일 텍스트 프로세서의 일종인데, asciidoc을 HTML 등으로 변환해주는 역할을 한다.


우리는 adoc을 yml로 변환해줄거기 때문에 필요없어서 이부분은 지우고,

mockMvc가 아닌 restAssured를 통해 테스틀 진행하기 때문에 mockMvc도 restAssured로 변경해주었다.

 

dependencies {
    testImplementation 'org.springframework.restdocs:spring-restdocs-restassured'
}

ext { 
    snippetsDir = file('build/generated-snippets')
}

test { 
    outputs.dir snippetsDir
}

요렇게만 추가를 해줬다.
RestDocs 적용법은 공식문서가 원체 잘나와있기에 패스.

3-2. yml 변환

위에서 언급 했듯, 오픈소스를 이용할거다.
이것도 나름 공식문서가 필요한 만큼은 잘되어있다.

plugins {
    id 'com.epages.restdocs-api-spec' version '0.18.2'
}

dependencies {
    testImplementation 'com.epages:restdocs-api-spec-mockmvc:0.18.2'
}

openapi3 {
    server = 'https://localhost:8080'
    title = 'My API'
    description = 'My API description'
    tagDescriptionsPropertiesFile = 'src/docs/tag-descriptions.yaml'
    version = '0.1.0'
    format = 'yaml'
}

이것도 공식문서에서 가져온건데,
의존성을 추가해주면 된다. 간단한다.

 

근데 마찬가지로 우린 mockMvc가 아닌 resuAssured를 사용할 것이므로
testImplementation 'com.epages:restdocs-api-spec-mockmvc:0.18.2' 얘를 지우고,
testImplementation 'com.epages:restdocs-api-spec-restassured:0.18.2' 얘를 넣어줬는데,

이러면 안된다.


restAssured를 사용하려면 저 두개가 모두 있어야 된다.


저거때문에 외않되를 연발 하다가, 똑같은 내용을 적용한 다른팀 크루에서 물어봐서 알게되었다.

두개가 다 있어야한다!


이 부분에 대해 공식문서에서 딱히 언급이 없어서 조금 헤멨던 것 같다.

사용하는 법 역시 간단하다.


RestDocs 공식문서를 보고 열심히 test코드를 수정했다면,

RestAssured.given(this.spec)
        .filter(document("{method-name}",
                "The API description",
                requestParameters(
                        parameterWithName("param").description("the param")
                ),
                responseFields(
                        fieldWithPath("doc.timestamp").description("Creation timestamp")
                )
        ))
        .when()
        .queryParam("param", "foo")
        .get("/restAssuredExample")
        .then()
        .statusCode(200);

이런식으로 돼있을 텐데,
filter()의 파라미터에 들어가는 값을 바꿔주면 된다.

 

현재 restDocs의 document가 아닌 com.epages.restdocs.apispec.RestAssuredRestDocumentationWrapper 얘의 document로 변경하면 된다.

설정은 끝났고 build.gradle 에 있는 저..저 재생? 버튼 누르면
테스트가 돌아가면서,

 

이런 식으로 문서가 생성된다!

728x90
728x90