Protobuf to OpenAPI 변환기
.proto 스키마를 붙여넣으세요. message 와 enum 이 components.schemas 로 출력된 OpenAPI 3.1 YAML 문서를 받아볼 수 있습니다 — 그대로 spec 에 붙여넣으면 됩니다.
입력 (.proto 스키마)
출력 (OpenAPI YAML)
이 도구가 하는 일
Protocol Buffers 스키마가 있고, 같은 형태에 대한 OpenAPI 문서를 원하는 프런트엔드, 파트너, QA 팀이 있다 — 보통 gRPC 서비스가 grpc-gateway 같은 것으로 HTTP 에도 노출되어 있기 때문입니다. 운영 환경에서는 빌드에 protoc-gen-openapiv2 를 세팅하는 게 정답이지만, 공유용이나 Swagger UI 에 넣을 빠른 spec 만 필요할 때는 과합니다. 이 변환기는 그 작업의 스키마 절반을 브라우저에서 처리합니다 — .proto 를 붙여넣고 YAML 을 복사하면 유효한 OpenAPI components 가 생깁니다.
출력은 최소한이지만 유효한 OpenAPI 3.1.0 문서로, 빈 paths: {} 와 Protobuf message 또는 enum 마다 한 항목씩 components.schemas 아래에 들어갑니다. OpenAPI 3.1 을 고르는 이유는 데이터 모델이 JSON Schema 2020-12 와 정렬되기 때문입니다 — int64, date-time, duration 같은 형식이 일급 시민이고, $ref 를 다른 키워드와 함께 둬도 3.0 시절의 재작성 꼼수가 필요 없는 버전입니다.
타입 매핑은 proto3 JSON 매핑 을 따릅니다: 32비트 정수는 type: integer, format: int32, 64비트 정수는 숫자 패턴이 붙은 type: string, format: int64(JSON 숫자는 2^53 이상에서 정밀도를 잃기 때문), repeated T 는 배열, map<K, V> 는 additionalProperties 가 있는 객체, 필드 이름은 서버가 실제 직렬화하는 형태와 맞도록 snake_case 그대로 유지됩니다. enum 은 값 이름을 담은 enum 리스트와 함께 type: string 으로 출력됩니다 — proto3 JSON 과 같습니다. 변환기는 전적으로 브라우저에서 동작하며, 스키마가 페이지 밖으로 나가지 않습니다.
사용 방법
세 단계입니다. 출력은 Swagger UI 에 그대로 넣거나 기존 spec 에 병합할 수 있는 YAML 문서입니다.
.proto 스키마 붙여넣기
왼쪽 에디터에 스키마를 떨어뜨리세요. 맨 위의 syntax = "proto3"; 는 있어도 좋지만 선택사항입니다. 파서는 중첩된 message 블록, enum 선언, oneof, map<K, V>, 필드 옵션을 처리합니다. 파일 간 import 문은 인식하지만 건너뜁니다 — 스키마끼리 서로 참조한다면 가져온 타입을 인라인으로 함께 붙여넣으세요.
출력에서 필드 이름은 proto3 JSON 인코더 기본값에 맞춰 snake_case 그대로 유지됩니다. gateway 가 camelCase JSON 이름으로 설정되어 있다면, 출력을 일괄 치환하거나 gateway 설정을 바꾸세요.
OpenAPI 출력 읽기
오른쪽: openapi: 3.1.0, info 블록, 빈 paths: {}, 그리고 components.schemas 아래 message 와 enum 이 들어간 YAML 문서가 있습니다. 중첩된 message 참조는 잎 이름에 대해 $ref: '#/components/schemas/MessageName' 을 쓰므로, .proto 가 중첩 타입을 선언해도 평면 참조가 동작합니다.
연결하기
파일을 Swagger UI 나 Redoc 인스턴스에 떨어뜨려 스키마가 어떻게 렌더되는지 확인하세요. 완전한 spec 으로 만들려면, gRPC-gateway 라우트를 가리키는 실제 paths 항목을 추가하거나 직접 작성하면 됩니다 — $ref 로 #/components/schemas/Order 를 가리키면 끝입니다.
실제로 시간이 절약되는 순간
프런트엔드나 파트너 팀과 스키마 공유하기
프런트엔드 팀이 gRPC 트랜스코드된 서비스를 사용하고 있습니다. 자기네 타입 생성기나 API 익스플로러에 꽂을 OpenAPI 문서를 요청해 왔습니다. .proto 를 붙여넣고 YAML 을 복사해서 보내세요. 그쪽 도구가 이미 이해하는 형식으로 스키마를 받게 됩니다.
새 HTTP 트랜스코드 API 의 spec 부트스트래핑
buf 와 함께 쓰는 grpc-gateway 로 gRPC 와 HTTP 양쪽에서 돌아갈 새 서비스를 띄우는 중입니다. components/schemas 섹션은 기계적인 작업 — 이 도구로 생성한 다음, 적절한 라우트 템플릿을 가진 paths 만 손으로 작성하세요. 전부 손으로 만드는 것보다 빠릅니다.
.proto 변경에 맞춰 Swagger UI 동기화 유지
팀에서는 사람이 읽는 API 문서로 Swagger UI 를 쓰지만, 진실의 출처는 .proto 파일에 있습니다. 백엔드 동료가 Order 에 shipping_address 를 추가했다면 — 여기서 schemas 섹션을 다시 생성해 spec 에 붙여 넣고 문서 업데이트를 배포하세요.
codegen 출력 점검하기
빌드의 일환으로 protoc-gen-openapiv2 를 돌렸더니 4000 줄짜리 YAML 파일이 나왔습니다. 특정 message 가 제대로 생겼는지 확인하려면, 그 .proto 파일 하나만 여기 붙여넣고 비교해 보세요. 깔끔한 OpenAPI 3.1 매핑이 어떻게 생겼는지 빠르게 참조할 수 있습니다.
자주 묻는 질문
왜 OpenAPI 3.0 이 아니라 3.1 인가요?
OpenAPI 3.1 은 데이터 모델을 JSON Schema 2020-12 와 맞췄습니다. 그래서 int64, date-time, duration 같은 형식이 잘 정의되어 있고, $ref 를 다른 키워드와 같이 둬도 3.0 에서 필요했던 어색한 회피책이 필요 없습니다. 최신 도구들(Redoc, Swagger UI 5, Stoplight, Spectral)은 3.1 을 잘 이해합니다. 레거시 도구를 위해 정말로 3.0 출력이 필요하다면 문서 맨 위의 openapi: 3.1.0 만 바꾸면 됩니다 — 나머지는 호환성이 충분해서 보통은 그대로 검증을 통과합니다.
int64 가 왜 숫자가 아니라 문자열로 나오나요?
JSON 숫자는 사실상 IEEE-754 double 이라 2^53 이상에서 정밀도가 깨집니다. 공식 proto3 JSON 매핑 은 int64, uint64, fixed64, sfixed64, sint64 를 JSON 문자열로 인코딩하라고 정합니다. 그래서 OpenAPI 스키마는 서버가 실제로 보내는 형태에 맞도록 type: string, format: int64, pattern: "^-?[0-9]+$" 을 사용합니다. 값이 작다고 가정하고 type: integer 를 쓰고 싶다면 출력을 일괄 치환하세요.
왜 paths 가 비어 있나요?
.proto 파일은 message 와 서비스를 기술하지, HTTP 라우트를 기술하지 않습니다. HTTP 트랜스코딩(경로, 메서드, 쿼리, 본문)은 별도로 설정합니다 — 보통 google.api.http 어노테이션이나 grpc-gateway 옵션으로요. 우리는 그것들을 파싱하지 않으므로 paths: {} 를 비워 둡니다. 재사용 가능한 기계적인 절반인 components/schemas 부분이 이 도구가 제공하는 것입니다.
왜 필드 이름이 snake_case 인가요?
proto3 JSON 이 기본적으로 그렇게 인코딩하기 때문입니다. .proto 의 order_id 는 camelCase 옵션(일부 인코더의 preserve_proto_field_names 또는 gateway 쪽 플래그)을 켜지 않으면 JSON 와이어 포맷에서 "order_id" 로 직렬화됩니다. OpenAPI 스키마를 snake_case 로 두면 서버가 실제로 보내는 JSON 과 일치합니다. 스택이 camelCase 라면 출력을 일괄 치환하면 됩니다.
중첩 message 는 어떻게 처리되나요?
각 Protobuf message 는 잎 이름(commerce.v1.Address 가 아니라 Address)을 키로 components.schemas 아래의 최상위 항목이 됩니다. 참조는 $ref: '#/components/schemas/Address' 를 사용합니다. 다른 패키지에 잎 이름이 같은 message 가 두 개 있으면, 두 번째가 첫 번째를 덮어씁니다 — 별도 문서로 나누거나 .proto 에서 이름을 바꾸세요.
google.protobuf well-known types 는 잘 이해하나요?
몇 가지는 그렇습니다. google.protobuf.Timestamp 는 type: string, format: date-time, Duration 은 type: string, format: duration, Empty 는 빈 객체, Any 는 일반 객체, Value 는 {}(임의의 JSON 값)로 렌더됩니다. 그 외 Google well-known types 에 대해서는 변환기가 현재 잎 이름에 대한 $ref 를 내보냅니다 — 그 스키마들을 직접 정의하거나, 참조를 적절한 원시 타입으로 바꾸시면 됩니다.
관련 도구
Protobuf 와 OpenAPI/JSON Schema 를 다루고 있다면, 다음 도구들이 잘 어울립니다: