같은 팀의 두 엔지니어가 같은 주에 두 개의 엔드포인트를 배포합니다. 하나는 created_at을 반환하고, 다른 하나는 createdAt을 반환합니다. 하나는 ?page=2로 페이지를 매기고, 다른 하나는 ?offset=20으로 페이지를 매깁니다. 하나는 최상위 error 객체에 오류를 넣고, 다른 하나는 message 문자열을 인라인으로 넣습니다. 검토자는 로직을 읽지 않고 명명 규칙을 읽기 때문에 둘 다 코드 검토를 통과합니다. 6개월 후, API 표면은 마치 다섯 개의 다른 회사에서 작성된 것처럼 보이며, 모든 클라이언트 통합은 특별한 경우를 필요로 합니다.
OpenAPI 린터는 이러한 이탈이 배포되기 전에 이를 잡아내기 위해 존재합니다. OpenAPI 문서를 읽고, 일련의 규칙(작업에는 설명이 필요하고, 스키마에는 예시가 필요하며, 속성 이름은 대소문자 표기 규칙을 따르고, 모든 응답은 미디어 타입을 선언해야 함)에 따라 실행하며, 규칙이 위반되면 빌드를 실패시킵니다. 이는 JavaScript의 ESLint 또는 Ruby의 RuboCop과 같은 아이디어이며, 애플리케이션 코드 대신 API 계약을 대상으로 합니다. 코드 포맷팅처럼 API 디자인 검토를 자동화할 수 있기를 바랐다면, 린터가 정확히 그 역할을 합니다.
버튼
OpenAPI 린터가 실제로 확인하는 사항
린터는 실행 중인 서버가 아닌 스펙 파일에서 작동합니다. openapi.yaml을 가리키면 모든 경로, 작업, 매개변수, 스키마 및 응답을 하나씩 탐색하며 규칙을 적용합니다. 규칙은 몇 가지 범주로 나뉩니다.
유효성. 이것이 유효한 OpenAPI 문서인가요? 모든 $ref가 해결되나요? 필수 키워드가 존재하나요? 이는 일반 스키마 유효성 검사와 겹치며, 대부분의 린터는 다른 어떤 것보다 먼저 이를 기본으로 수행합니다.
완전성. 모든 작업에 operationId, 요약, 설명이 있나요? 모든 매개변수가 자체적으로 설명되나요? 모든 스키마에 example이 포함되어 있나요? 이러한 규칙은 생성된 문서와 SDK를 실제로 사용할 수 있게 만들며, 사람이 가장 많이 잊어버리는 부분입니다.
일관성. 이것이 진짜 핵심입니다. 속성 이름은 하나의 대소문자 표기 규칙을 사용합니다. 경로 세그먼트는 복수 명사입니다. 오류 응답은 하나의 형식을 공유합니다. 모든 2xx 응답은 application/json을 선언합니다. 상태 코드는 HTTP 스펙이 의도하는 방식으로 사용됩니다. 이 중 어느 것도 단독으로는 버그가 아니지만, 이들이 함께 모여 설계된 느낌을 주는 API와 조립된 느낌을 주는 API의 차이를 만듭니다.
사내 스타일. 귀하의 자체 규칙입니다. 모든 엔드포인트에 태그가 지정되어야 할 수도 있습니다. DELETE는 204를 반환해야 할 수도 있습니다. 내부 전용 필드에는 접두사가 붙어야 할 수도 있습니다. 이것들은 다른 누구도 가지고 있지 않은 규칙이며, 이를 작성하는 능력은 함께 작업할 수 있는 린터와 싸워야 하는 린터를 구분하는 요소입니다.
규칙에는 심각도(오류, 경고, 정보, 힌트)가 있습니다. 오류는 빌드를 실패시키고, 경고는 표시되지만 통과시킵니다. 이 심각도 조절 기능 덕분에 기존 API에 린팅을 도입할 때 첫날부터 4,000개의 위반 사항에 허덕이지 않아도 됩니다. 모든 것을 경고로 시작하고, 가장 심각한 것을 수정한 다음, 진행하면서 규칙을 오류로 승격시키세요. 이러한 규칙이 중요한 이유와 팀이 대규모로 이를 적용하는 방법에 대한 개념적 측면은 최고 기업들이 API 설계 일관성을 보장하는 방법에서 더 자세한 배경을 확인할 수 있습니다.
주요 OpenAPI 린터 옵션
각 도구가 어디에 적합한지에 대한 솔직한 평가와 함께 알아두면 좋은 도구들입니다.
Spectral
Stoplight의 Spectral은 사실상의 표준입니다. OpenAPI 2.0 및 3.x(및 AsyncAPI, JSONPath를 통한 모든 JSON 또는 YAML)를 린팅하는 오픈소스 CLI 및 라이브러리입니다. 상식적인 규칙을 다루는 내장 spectral:oas 규칙 세트와 함께 제공되며, 진정한 강점은 사용자 정의 규칙입니다. JSONPath 스타일의 given 셀렉터와 then 함수를 사용하여 검사할 내용을 YAML 파일에 모두 기술합니다. 방대한 내장 함수(truthy, pattern, casing, length, enumeration) 카탈로그가 있으며, 선언적 형식이 표현할 수 없는 로직이 필요할 때 JavaScript를 사용할 수 있습니다.

강점: 어디에나 존재하며, 가장 큰 규칙 생태계를 가지고 있고, VS Code 및 기타 에디터 확장 기능이 있으며, Node가 실행되는 모든 곳에서 실행됩니다. 업계 전체가 인정하는 하나의 도구를 원한다면 바로 이것입니다. 단점은 중요하지 않은 규칙을 작성하려면 JSONPath와 궁극적으로 Spectral의 함수 API를 배워야 한다는 것입니다. 작성에 대해 더 깊이 알고 싶다면 TypeScript로 사용자 정의 Spectral 규칙 구축에서 전체 과정을 자세히 설명하고 있습니다.
extends: ["spectral:oas"]
rules:
operation-operationId: error
operation-description: warn
property-casing:
description: Properties must be camelCase
given: $.components.schemas..properties[*]~
severity: error
then:
function: casing
functionOptions:
type: camel
실행:
npx @stoplight/spectral-cli lint openapi.yaml
Redocly CLI
Redocly의 CLI는 린팅을 번들링 및 문서 미리보기와 함께 제공합니다. 린터는 redocly.yaml 설정을 읽고, 내장 규칙 세트를 제공하며, 구성 가능한 규칙 세트와 JavaScript로 작성된 사용자 정의 플러그인을 지원합니다. Redocly를 문서화에 이미 사용하고 있는 팀은 추가 종속성 없이 동일한 툴체인에서 린팅을 얻을 수 있으며, 내장 규칙은 문서가 잘 렌더링되도록 하는 데 중점을 둡니다.

강점: 문서 및 번들링 워크플로우와의 긴밀한 통합, 적절한 기본 설정, 그리고 Redocly 생태계에 익숙하다면 편안하게 느껴질 설정 형식입니다. 이미 Redocly를 사용하지 않는다면, 규칙 라이브러리는 Spectral보다 작고 사용자 정의 규칙에 대한 설명이 덜 광범위하게 문서화되어 있습니다.
npx @redocly/cli lint openapi.yaml
Vacuum
Vacuum은 Go로 작성된 최신 린터로, 속도를 위해 개발되었습니다. Spectral 규칙 세트와 호환되므로, 기존 .spectral.yaml 파일을 가리키면 대규모 스펙에 대해 훨씬 더 빠르게 동일한 검사를 실행할 수 있습니다. 수십 개의 대규모 API 문서가 있는 모노레포의 경우, 런타임 차이가 실제로 체감됩니다.

강점: 빠르고, Spectral 규칙 세트와 호환되며, Node 런타임 없이 단일 바이너리로 작동합니다. 스펙이 작다면 속도 이득은 눈에 띄지 않으며, 생태계와 에디터 도구는 Spectral보다 아직 초기 단계이므로, 처음부터 선택하기보다는 CI 가속기로서 가장 매력적입니다.
Swagger 및 openapi-spec-validator
린터와 혼동하지 않도록 이름만 언급할 가치가 있습니다. Swagger Editor와 swagger-cli/openapi-spec-validator는 문서가 유효한 OpenAPI인지 확인합니다. 이는 일관성이나 사내 스타일이 아닌 유효성만을 다룹니다. OpenAPI 사양에 이를 금지하는 조항이 없기 때문에, 모든 속성 이름이 다른 스펙이라도 문제없이 통과시킬 것입니다. 유효성 검사는 필요하지만, 그것은 최소한의 기준일 뿐 최고 수준이 아닙니다. Swagger 계열 도구와 완전한 설계 플랫폼 중에서 선택하는 경우, 그 장단점은 API도 테스트하는 Swagger 대체 도구에 설명되어 있습니다.
Apidog의 설계 시점 검사
위의 도구들은 파일이 생성된 후에 실행됩니다. 불일치를 잡아낼 수 있는 다른 시점은 파일이 존재하기 전, 즉 엔드포인트를 설계하는 동안입니다. Apidog은 설계 우선 플랫폼입니다. 시각적 편집기에서 엔드포인트와 데이터 스키마를 구축하며, 진행하면서 프로젝트의 내부 일관성을 유지합니다. 재사용 가능한 데이터 스키마는 동일한 모델이 엔드포인트마다 재정의되는 대신 모든 곳에서 참조됨을 의미하며, 이는 명명 이탈의 전체 클래스를 원천적으로 방지합니다. 공유 응답 컴포넌트도 오류 형식에 대해 동일한 역할을 합니다.
Apidog은 Spectral 규칙 세트의 직접적인 대체제가 아닙니다. .spectral.yaml 규칙을 커밋했다면 계속 실행하세요. Apidog이 바꾸는 것은 린터가 처음부터 찾아내는 양입니다. 설계 인터페이스가 재사용을 강제하면, 린터는 수많은 위반 사항을 찾아내는 대신 가끔씩 불일치를 잡아내는 역할을 합니다. 또한 Apidog은 표준 OpenAPI 3.x를 가져오고 내보내므로, CI에서 Spectral 또는 Vacuum에 넘겨주는 파일은 동일한 아티팩트가 되어 두 계층이 경쟁하지 않고 서로 보완하게 됩니다.
오늘 당장 실행할 수 있는 린터 설정
좋은 설정은 세 곳에서 검사를 실행하며, 각기 다른 역할을 합니다. 편집기는 즉각적인 피드백을 제공합니다. pre-commit 훅은 명백한 실수를 로컬에서 중단시킵니다. CI는 아무도 건너뛸 수 없는 관문입니다. 각 계층은 다음과 같습니다.
계층 1: 편집기
Spectral VS Code 확장을 설치하고 .spectral.yaml 파일을 레포지토리 루트에 추가하세요. 확장은 이를 자동으로 인식하여 스펙을 편집할 때 오타가 빨간색 물결 밑줄이 생기는 것과 동일한 방식으로 위반 사항에 밑줄을 표시합니다. 이는 개발자가 커밋하기 전에 문제를 해결하므로 가장 저렴한 피드백 루프입니다. 다른 것을 구성할 필요가 없습니다. 레포지토리의 파일이 규칙에 대한 단일 진실 공급원입니다.
계층 2: pre-commit
손상된 스펙이 원격 저장소에 도달하지 않도록 훅을 추가하세요. package.json 스크립트와 Git 훅을 사용하는 것으로 충분합니다.
{
"scripts": {
"lint:api": "spectral lint openapi.yaml --fail-severity=error"
}
}
# .git/hooks/pre-commit (or via husky)
#!/bin/sh
npm run lint:api || {
echo "OpenAPI lint failed. Fix the spec before committing."
exit 1
}
--fail-severity=error 플래그가 중요한 부분입니다. 이는 린터에게 오류가 발생할 때만 0이 아닌 값으로 종료하도록 지시하므로, 경고는 여전히 출력되지만 커밋을 차단하지는 않습니다. 이를 통해 규칙을 계속 승격하는 동안에도 훅을 사용할 수 있습니다.
계층 3: CI
이것이 중요한 관문입니다. 팀원이 --no-verify로 우회할 수 없기 때문입니다. GitHub Actions 단계는 다음과 같습니다.
name: API lint
on: [pull_request]
jobs:
spectral:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npx @stoplight/spectral-cli lint openapi.yaml --fail-severity=error
스펙이 오류 수준 규칙을 위반하면 작업이 실패하고, 풀 리퀘스트에 빨간색 체크 표시가 나타나며, 누군가가 이를 수정할 때까지 병합이 차단됩니다. 이것이 전체 강제 메커니즘입니다. 대시보드도 없고 잔소리도 없습니다. 규칙은 통과하거나 실패합니다.
계층 4: 스펙이 설명하는 API 테스트
린터는 스펙이 잘 구성되어 있고 일관성이 있음을 증명합니다. 실행 중인 API가 스펙과 일치하는지에 대해서는 아무 말도 하지 않습니다. 그 간극은 계약 불일치가 숨어 있는 곳입니다. 즉, 세 번의 릴리스 전에 서버가 더 이상 따르지 않는 동작을 설명하는 아름답게 린팅된 문서입니다. 이를 해결하려면 동일한 파이프라인에서 실제 API에 대해 테스트를 실행해야 합니다.
여기에 Apidog CLI가 린터 옆에 들어맞습니다. apidog-cli는 npm 패키지이며, 명령줄에서 Apidog 테스트 시나리오를 실행하여 린트 단계 직후 CI에 삽입할 수 있습니다.
npm install -g apidog-cli
apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 -e 1629989 -r cli,junit
테스트가 실패하면 apidog run 명령은 0이 아닌 값으로 종료됩니다. 이는 모든 CI 단계가 의존하는 동일한 계약이므로, 실패한 테스트는 실패한 린트와 마찬가지로 병합을 차단합니다. -r junit 리포터는 CI 대시보드가 통과/실패 트리로 구문 분석하는 XML을 내보내고, -e는 동일한 시나리오를 중복 없이 스테이징 또는 프로덕션 환경으로 지정합니다. CLI는 OpenAPI 3.x 문서를 import할 수도 있으므로, 린터가 확인하는 파일과 Apidog이 테스트하는 파일은 동일합니다. 리포터 및 종료 코드 처리 기능을 포함한 전체 파이프라인 패턴에 대한 자세한 내용은 CI/CD 파이프라인에서 Apidog CLI 실행 가이드를 참조하세요. 특히 GitHub를 사용 중이라면 GitHub Actions의 Apidog CLI에 복사하여 붙여넣을 수 있는 워크플로우가 있습니다.
먼저 린트하고, 두 번째로 테스트합니다. 린트 단계는 빠르며 설계 문제를 잡아내고, 테스트 단계는 더 느리지만 동작 문제를 잡아냅니다. 이들을 두 단계로 실행하면 풀 리퀘스트는 둘 다 통과해야 합니다.
고통 없이 규칙 세트 선택 및 적용하기
도구를 선택하는 것은 쉬운 부분입니다. 이미 존재하는 API에 적용하는 것은 팀이 주춤하는 지점인데, 성숙한 스펙에서 첫 실행 시 수백 개의 위반 사항이 반환되고 이에 대한 명백한 반응은 모든 것을 끄는 것이기 때문입니다.
규칙을 0개부터 시작하지 말고, 모든 규칙을 오류로 설정하여 시작하지 마세요. 내장 규칙 세트(spectral:oas)를 시작으로 추가하는 모든 것을 warn으로 설정하세요. 이를 실행하고, 개수를 확인한 다음, 유효성 오류부터 수정하세요. 그것들이 진짜 버그이기 때문입니다. 그런 다음 클라이언트에게 가장 중요한 두세 가지 일관성 규칙(일반적으로 속성 대소문자 표기 및 단일 오류 형식)을 선택하고, 그것들만 error로 승격시키세요. 다른 모든 것은 경고로 남겨둡니다. 매 스프린트마다 코드베이스가 따라잡을 때마다 한두 개의 경고를 오류로 더 승격시키세요. 한 분기 내에 전체 규칙 세트가 적용되며, 그 과정에서 아무도 배포를 멈출 필요가 없습니다.
사내 스타일 규칙은 아껴서 작성하세요. 모든 사용자 정의 규칙은 누군가가 유지보수하고 다음 채용자에게 설명해야 하는 코드입니다. 규칙은 "그럴 수도 있다"는 이유가 아니라, 실제로 위반이 문제를 일으켰을 때만 제자리를 차지합니다. 작성하는 규칙에 대해서는 설계 계층에 의존하여 규칙 발생 빈도를 낮추세요. 예를 들어, 스키마가 중앙 정의에서 재사용되는 경우, 이름이 한 곳에서 정의되므로 속성 대소문자 규칙은 거의 트리거되지 않습니다. 어떤 규칙을 강제할 가치가 있고 어떤 규칙이 불필요한 논쟁을 유발하는지에 대한 개념적 프레임워크는 API 설계 모범 사례에 다루어져 있습니다.
원시 YAML이 아닌 다른 언어로 설계하더라도 린터는 여전히 적용됩니다. TypeSpec은 OpenAPI로 컴파일되며, 생성된 문서를 동일한 방식으로 린트합니다. 린터는 파일이 어떻게 작성되었는지 신경 쓰지 않고, 오직 파일의 내용만을 신경 씁니다.
린터가 더 큰 설계 루프에 어떻게 들어맞는가
린터는 설계 우선 워크플로우의 한 가지 제어 수단일 뿐, 전체가 아닙니다. 전체 루프는 다음과 같습니다. 계약을 설계하고, 린트하고, 클라이언트가 이를 기반으로 구축할 수 있도록 모킹하고, 구현을 테스트하고, 문서화를 게시합니다. 어떤 단계라도 건너뛰면 다른 단계의 가치가 떨어집니다. 아무도 모킹하지 않는 린트된 스펙은 여전히 프론트엔드 작업을 막습니다. 아무도 테스트하지 않는 모킹된 스펙은 여전히 현실과 괴리됩니다.
해당 루프에서 설계를 우선시하는 이유는 린팅이 작동하는 이유와 같습니다. 즉, 문제를 가장 저렴하게 해결할 수 있는 곳에서 잡는 것입니다. 설계 도구에서 속성 이름을 변경하는 것은 한 번의 편집입니다. 세 팀이 이전 이름에 맞춰 배포한 후 변경하는 것은 마이그레이션입니다. 린터는 파일의 일관성을 강제하고, 설계 우선 프로세스는 파일이 존재하기 전의 결정에 대해 이를 강제합니다. 시퀀싱에 대한 더 넓은 주장을 원한다면 API 우선 vs API 설계 우선 vs 코드 우선이 장단점을 설명하고, 계약 우선 API 설계 도구가 이를 지원하는 도구를 다룹니다.
버튼
Apidog은 이 전체 루프를 한 곳에서 처리합니다. 재사용 가능한 스키마로 설계하고, 즉시 모킹하고, CI에서 CLI로 테스트하며, 표준화된 린터에 사용할 깔끔한 OpenAPI를 내보냅니다. 린터는 여전히 할 일이 있지만, 잡아낼 것이 줄어들 뿐입니다.
버튼
