글 작성자: 개발섭

테스트 코드로 API docs 관리를 할 수 있다고?

Spring Rest Docs 라이브러리는 테스트 코드를 작성하면 Asciidoc 파일을 통해서 테스트 코드를 구현할 수 있다.

하지만, 불편한 점들이 눈에 밟혔다. Asciidocs 파일에 대한 이해도가 반드시 필요했으며, Rest Docs가 기본적으로 제공하는 Docs 제공 하는 페이지가 나랑 취향이 너무 안맞았다. 솔직히 보면서 이렇게 까지 써야할까라는 생각을 했었는데… 웹사이트를 뒤적뒤적 거리다 마침 RestDocs 테스트 코드를 바탕으로 Swagger 문서를 구성할 수 있는 라이브러리를 찾아, 그 기능을 사용해보기로 했다.

구축기

가장 본 바탕이 되었던 이 레포지토리를 기준으로 개발 환경 세팅 방법을 확인하자.

https://github.com/traeper/api_documentation

 

GitHub - traeper/api_documentation: OpenApi Spec을 이용한 API 문서화

OpenApi Spec을 이용한 API 문서화. Contribute to traeper/api_documentation development by creating an account on GitHub.

github.com

위의 구축기는 기능적인 면에서는 좋았던 점이 많은데, 하나 구축 도중에 스스로가 개선해봐도 괜찮겠다고 생각했었던 부분이 있어서 그 부분을 중점적으로 설명해보도록 하겠다.

개선해봤던 점

위의 Repository에서는 Spring boot가 swagger의 index.html을 그대로 정적 서빙했었다. 근데 곰곰히 생각해보면, 굳이 정적파일을 Spring Boot에서 서빙해야할까?

현재 프로젝트에서는 Reverse Proxy로 Nginx를 사용하고 있었고, 관련한 정적 파일들을 모두 Nginx에서 관리하는것이 효과적이라고 생각했다.

물론, Spring Boot의 상태에 따라서 Swagger 자체를 접근 불가능하게 하는 방법도 있겠으나, 일단 기본적으로 API Spec을 제공한다는 측면에서 나는 Nginx으로 Swagger의 index파일을 서빙하는 방식으로 배포 방식을 변경했다. 추가적으로 API Spec이 개발간의 변경 사항이 분명히 존재할 수 있겠으나, 같이 협업하는 개발자들은 API Docs를 통해서 개발을 진행하기 때문에, 정말 대격변적으로 변경하는 케이스가 아니라면, 지속적인 노출이 더욱 중요하다고 생각한다.

Nginx 정적 서빙하도록 구축하기

1. Swagger UI Installation

'Static files without HTTP or HTML' 부분에서 latest release를 다운 받아 /dist 디렉토리만 복사해줍니다.

2. Nginx의 nginx.conf 혹은 default.d/*.conf에 index.html을 서빙하도록 설정

#nginx.conf
server {
        listen       80;
	       #...

        # 이 설정때문에 사실상 아래의 설정이 들어가게된다. 
        include /etc/nginx/default.d/*.conf; 

}

# default.d/swagger.conf
location /swagger {
        root #swagger index파일이 있는 주소를 작성해준다. 
				# 단, location 주소도 영향을 받으니, ~/app/swagger/index.html 이런 위치라면,
				# ~/app 만 작성해줘야 위의 location의 작성한 swagger path가  
        index index.html;
}

이렇게 설정하게 되면, 해당 주소의 /swagger 주소로는 index.html으로 화면이 이동하게 된다.

3. index.html 내부의 정적파일 주소 변경 및 yaml 파일 매핑

<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>

<script>
      window.onload = function() {
        // Begin Swagger UI call region
        const ui = SwaggerUIBundle({
          url: "./openapi3.yaml",
          dom_id: '#swagger-ui',
          deepLinking: true,
          presets: [
            SwaggerUIBundle.presets.apis,
            SwaggerUIStandalonePreset
          ],
          plugins: [
            SwaggerUIBundle.plugins.DownloadUrl
          ],
          layout: "StandaloneLayout"
        });
        // End Swagger UI call region

        window.ui = ui;
      };
</script>

과 같이 정적 위치와 yaml파일을 타게팅 할 수 있도록 스크립트문을 짜준다. openapi3.yaml 파일 역시 이 Swagger 파일이 있는 폴더 하위에 위치해야 합니다.

이렇게 하면, nginx를 통해서 index.html이 서빙되긴하는데, 이제는 내가 배포 할때마다 이 openapi3.yaml 파일을 옮겨줘야한다. 그 작업만 선행되면, 매번 배포때마다 nginx를 통해서 API docs를 관리할 수 있게 되어진다.

EC2 배포 방식

배포 방식 역시 공유해보려한다, 이 배포 방식은 Ec2 & CodeDeploy & github action 기준을 통해서 배포 된다는 점을 알아주면 좋을 것 같다.

다른 배포 방식, 예를 들면, ECS, ECK와 같은 배포 방식에는 다른 배포 방식을 택해야 할 것 같다.

가장 기본이 되는 배포 방식 자체는 github action를 통해 구성된 yaml파일과 shell script으로 구성했습니다.

0. build과정에 필요없는 작업 삭제시키기

tasks.register<Copy>("copyOasToSwagger")

CopyOasToSwagger는 서버 내부 정적파일 서빙하는 경우에만 해당하는 케이스로 빌드 과정에서 빠져도 괜찮습니다.

1. build 과정에 만들어진 openapi3.yaml을 s3로 옮기자

 - name: openAPI3.yaml S3 이동
      run: aws s3 sync ./build/api-spec/ s3://s3위치/dev/

2. Code deploy에서 실행할수 있도록, appspec.yml에서, Script문 실행문 추가

ApplicationStart:
    - location: ./script/swagger.sh
      timeout: 30
      runas: root

3. 스크립트문 작성 (swagger.sh)

aws s3 cp s3://~~~/openapi3.yaml /home/~~~/swagger/ 2> /dev/null

if [ $? = 1 ]; then
  echo "########## openapi3가 재대로 sync 되지 않았습니다 #######"
  exit;
else
  echo "##############"
  echo "> swagger 페이지 재배포 시작"
  echo "##############"
  systemctl restart nginx.service ## 재시작해도 안해도 되는데 일단 재실행
fi

이렇게 되면, 코드 배포시마다 API Docs가 추가되는 것을 확인할 수 있을 겁니다.

 

물론 이렇게만 작성한다면, 베스트지만...

Rest Docs + Swagger 변환 과정에서 이슈들이 종종 있었고, 이걸 해결하는 과정들이 꽤 많이 복잡했었다. 혹은 어이없는 이유로 되는 경우도 왕왕 있었고... 그래서 그런 문제들을 위해서 해결하는 과정이 반드시 필요했었는데, 이슈들과 구축기는 좀 분리될 필요가 있어 보여서, 이어서 이슈 정리를 하는 글을 다시 작성하고 이어서 링크를 붙이도록 할 예정이다.