
BE API 는 수정이 잦을 수밖에 없다.
만약 기획 변경이나 잘못된 설계가 진행된 경우, API 의 필드값, 스키마 혹은 로직 자체가 수정되어야 한다.
특히 바쁜 일정과 변경점이 잦은 프로젝트일수록 API 는 자주 변화하고 자주 수정된다.
현재 사내에서는 백엔드 완성 이전에 프론트가 작업을 착수하고 있는데, 프론트 개발 도중 API 가 수정되는 일이 발생한다.
문제점은 프론트팀에서 이를 탐지하지 못 한다는 것이다.
즉, 본인은 기존 API 스펙에 맞게 구현하였음에도, 변경된 API 스펙을 인지하지 못 해 장애가 발생하는 상황이 생기는 것이다.
실제로 아래와 같은 슬랙을 주고받았다.

이러한 문제점이 생각보다 심각함을 알게되었고, 내부설문조사를 해보았다.
아래는 프론트팀에서 제기한 문제점들을 나열한 것이다.
그렇다면 이를 해결할 수는 없을까?
필자는 변경점이 존재할 때 프론트팀에 공지할 수 있도록 하고자 한다.
API 스펙 변경 시 swagger diff 오픈소스들을 활용하여 배포 파이프라인에서 변경점을 감지하고,
이를 slack 에 notify 될 수 있도록 구현해보고자 한다.
아래와 같은 설계로 접근해보고자 한다.
💡
- 기존 서버의 swagger json(혹은 yaml) 을 다운로드
a. curl 명령어를 사용하여 다운curl -o swagger.json ${api-path}- 배포할 코드의 swagger json(혹은 yaml) 을 다운로드
a. 서버 실행 후 localhost 내의 swagger.json 을 다운로드- 파이프라인에서 diff 지원 오픈소스 실행
b. diff 지원 오픈소스 다운로드
c. 변경점 분석결과 가져오기
d. 만약 변경점 분석결과 존재 시 슬랙에 dm 전송
docker run --rm --name openapi-diff -v ~/:/specs openapitools/openapi-diff:latest /specs/swagger-sample-01.yaml /specs/swagger-sample-02.yaml
Status: Downloaded newer image for openapitools/openapi-diff:latest
==========================================================================
== API CHANGE LOG ==
==========================================================================
Swagger Petstore - OpenAPI 3.0
--------------------------------------------------------------------------
-- What's Changed --
--------------------------------------------------------------------------
- PUT /pet
Request:
- Changed application/json
Schema: Broken compatibility
Missing property: photoUrls (array)
- Changed application/xml
Schema: Broken compatibility
Missing property: photoUrls (array)
- Changed application/x-www-form-urlencoded
Schema: Broken compatibility
Missing property: photoUrls (array)
Return Type:
- Changed 200 OK
Media types:
- Changed application/json
Schema: Broken compatibility
Missing property: photoUrls (array)
- Changed application/xml
Schema: Broken compatibility
Missing property: photoUrls (array)
- POST /pet
Request:
- Changed application/json
Schema: Broken compatibility
Missing property: photoUrls (array)
- Changed application/xml
Schema: Broken compatibility
Missing property: photoUrls (array)
- Changed application/x-www-form-urlencoded
Schema: Broken compatibility
Missing property: photoUrls (array)
Return Type:
- Changed 200 OK
Media types:
- Changed application/json
Schema: Broken compatibility
Missing property: photoUrls (array)
- Changed application/xml
Schema: Broken compatibility
Missing property: photoUrls (array)
- GET /pet/findByStatus
Return Type:
- Changed 200 OK
Media types:
- Changed application/json
Schema: Broken compatibility
Missing property: [n].photoUrls (array)
- Changed application/xml
Schema: Broken compatibility
Missing property: [n].photoUrls (array)
- GET /pet/findByTags
Return Type:
- Changed 200 OK
Media types:
- Changed application/json
Schema: Broken compatibility
Missing property: [n].photoUrls (array)
- Changed application/xml
Schema: Broken compatibility
Missing property: [n].photoUrls (array)
- GET /pet/{petId}
Return Type:
- Changed 200 OK
Media types:
- Changed application/json
Schema: Broken compatibility
Missing property: photoUrls (array)
- Changed application/xml
Schema: Broken compatibility
Missing property: photoUrls (array)
--------------------------------------------------------------------------
-- Result --
--------------------------------------------------------------------------
API changes broke backward compatibility
--------------------------------------------------------------------------
openapi-diff --help 에서 볼 수 있듯이 다양한 기능을 제공한다.openapi-diff --help
사용법: openapi-diff <old> <새>
--asciidoc <파일> 지정된 파일에 asciidoc으로 diff를 내보냅니다.
--debug 디버깅 정보를 인쇄합니다.
--error 오류 정보 인쇄
-h,--help 이 메시지를 인쇄합니다.
--header <property=값> 권한 부여를 위해 지정된 헤더 사용
--html <파일> 지정된 파일에서 diff를 html로 내보내기
--info 추가 정보 인쇄
--json <파일> 지정된 파일에서 diff를 json으로 내보내기
-l,--log <레벨> 로그에 지정된 레벨을 사용합니다(TRACE, DEBUG,
정보, 경고, 오류, 꺼짐). 기본값입니다: ERROR
--markdown <파일> 지정된 파일에서 diff를 마크다운으로 내보내기
--off 정보 출력 안 함
--query <property=value> 권한 부여를 위해 쿼리 매개변수 사용
--state diff 상태만 출력 상태: no_changes,
호환되지 않음, 호환 가능
--fail-on-incompatible API 변경으로 인해 이전 버전과의 호환성이 깨진 경우에만 실패합니다.
--fail-on-changed API가 변경되었지만 이전 버전과 호환되는 경우 실패합니다.
--config-file 기본 동작을 재정의하는 구성 파일. 지원되는 파일 형식 .yaml
--config-prop 키:값 형식으로 기본 동작을 재정의하는 구성 속성(예: my.prop:true)
--trace 추가 상세 정보 표시
--버전 버전 정보를 인쇄하고 종료
--warn 경고 정보를 인쇄합니다.
sudo curl -fsSL <https://raw.githubusercontent.com/tufin/oasdiff/main/install.sh> | sudo sh
oasdiff -h 를 통해 볼 수 있듯이 아래 기능들을 지원한다.사용 가능한 명령:
breaking 변경 내용 표시
변경 로그 변경 로그 표시
checks 검사 표시
완료 지정된 셸에 대한 자동 완성 스크립트를 생성합니다.
diff 차이점 보고서 생성
평탄화 allOf 병합
도움말 모든 명령에 대한 도움말
qr oasdiff 리포지토리의 QR 코드 표시
요약 diff 요약 생성
jihoon@HAMA:~$ oasdiff changelog swagger-sample-01.yaml swagger-sample-02.yaml -f html
<html>
<head>
<style>
@import url(//fonts.googleapis.com/css?family=Nunito);
* {
font-family: 'Nunito','Helvetica Neue',Helvetica,Arial,sans-serif;
}
.title {
margin: 1em 0 0.5em 0;
font-size: 36px;
}
.path {
color: #016BF8;
,,,,
Tufin/oasdiff 를 사용하기로 결정했다. 이유인 즉슨,,
변경 전 값 → 변경 후 값 으로 분석해줬다.필자는 GitLab 의 파이프라인에 통합하여 CI/CD 과정에서 처리될 수 있게끔 하고자 하였다.
대충 프로세스는 아래와 같다.
빌드 스테이지에서 자바애플리케이션을 컴파일(빌드) 하여 결과물 app.jar 를 얻는다.
배포 스테이지에서 app.jar 를 서버에 배포(앱 실행)한다.
oas-diff 스테이지에서 배포된 버전의 oas(latest.json)를 얻고, oasdiff 로 옛날 버전의 origin.json 파일과 비교하여 변경점을 깃랩서버에 저장한다.
(최초 실행시 origin.json 이 없다. 캐시되기 전이므로, 두번째 배포부터 비교되기 시작한다.)
oas-cache 스테이지에서 배포된 버전의 oas(origin.json)를 얻고, 러너에 캐시한다.
위 과정을 다음 파이프라인에서 반복한다. 반복되면 oas-diff 스테이지에서 이전 파이프라인의 캐시된 origin.json 과 현재 배포중인 latest.json 을 반복적으로 비교하게된다.
비교한 파일은 changelog_slack.md 로 저장되는데 이것을 슬랙봇의 특정 채널 웹훅으로 전송한다.
이에 따른 CI 는 아래와 같다.
...
build:
...
deploy:
...
environment:
name: development
url: **$DEV_OAS_URL**
...
oas-diff:
image: python:3.10
stage: Diff
before_script:
- curl -fsSL <https://raw.githubusercontent.com/tufin/oasdiff/main/install.sh> | sh
script:
- |
for i in {1..20}; do
if curl -s -o /dev/null -w '%{http_code}' $DEV_OAS_URL | grep -q "200"; then
**curl -o latest.json $DEV_OAS_URL**
echo "$i"
break
fi
echo "Wating for API server to be ready... Retry $i"
sleep 4
done
- **oasdiff changelog origin.json latest.json -f markup > changelog.md**
- bash mrkdwn_parser.sh
**artifacts:
paths:
- ./changelog_slack.md**
expire_in: 3 days
needs: [deploy]
allow_failure: true
**cache:
key: shared-cache
paths:
- ./origin.json**
rules:
- if: $CI_COMMIT_REF_NAME == "develop"
oas-cache:
image: python:3.10
stage: Diff
script:
- |
for i in {1..20}; do
if curl -s -o /dev/null -w '%{http_code}' $DEV_OAS_URL | grep -q "200"; then
**curl -o origin.json $DEV_OAS_URL**
echo "epoch $i"
break
fi
echo "Wating for API server to be ready... Retry $i"
sleep 2
done
artifacts:
paths:
- ./origin.json
expire_in: 3 days
needs: [oas-diff]
**cache:
key: shared-cache
paths:
- ./origin.json**
**policy: push**
rules:
- if: $CI_COMMIT_REF_NAME == "develop"
when: always
post-slack-message:
image: python:3.10
stage: Slack
before_script:
- apt-get update && apt-get install -y jq
script:
- line_number_of_changelog_result=$(wc -l changelog_slack.md | awk '{print $1}')
- |
if [ "$line_number_of_changelog_result" -gt 3 ]; then
**curl -H "Content-type: application/json" \\
--data "$(cat ./changelog_slack.md | jq -Rs --arg channel "$SLACK_CHANNEL_ID" '{"channel":$channel,"blocks":[{"type":"section","text":{"type":"mrkdwn","text":.}}]}')" \\
-X POST $POST_API_URL**
fi
allow_failure: true
needs: [oas-diff, oas-cache]
rules:
- if: $CI_COMMIT_REF_NAME == "develop"
위 구조를 통해 아래와 같이 슬랙 메세지가 오는 것을 확인할 수 있었다.

다만 oasdiff 결과물인 영어로 처리되어 나오는 것을 볼 수 있었다. 😭
Devops/AI 팀의 지원을 통해 이를 해결할 수 있었다.
n8n 워크플로우 기반으로 한글로 번역, 요약되어 볼 수 있게끔 처리해주셨다.
(Special Thx to 오대리님,,)
GitLab 파이프라인에서 비교결과파일(changelog.md)을 슬랙으로 바로 전송하지 않고 n8n 웹훅 노드에 전송(POST)한다.
전송된 changelog.md 를 AI 프롬프트를 통해 파싱하고 전처리한다.
다시 HTTP Request(POST)로 슬랙 API 를 호출해 채널에 전송하는 식이다.
위 구조를 통해 한글 요약본을 받아볼 수가 있었다 :-)

굳이 n8n & ML model 의 도움이 필요할까?
API 변경점 추적이 어렵다
https://github.com/tinohager/swagger-diff
https://github.com/Sayi/swagger-diff#usage
https://github.com/civisanalytics/swagger-diff
https://bitbucket.org/atlassian/openapi-diff/src/master/
https://github.com/OpenAPITools/openapi-diff
https://github.com/Tufin/oasdiff