Conversor Protobuf a OpenAPI
Pega un esquema .proto. Obtén un documento YAML de OpenAPI 3.1 con los messages y enums emitidos como components.schemas — listo para pegarlo en tu spec.
Entrada (esquema .proto)
Salida (OpenAPI YAML)
Qué hace esta herramienta
Tienes un esquema Protocol Buffers y un equipo de frontend, partner o QA que quiere un documento OpenAPI con las mismas formas — normalmente porque el servicio gRPC también está expuesto sobre HTTP a través de algo como grpc-gateway. Configurar protoc-gen-openapiv2 en tu build es la respuesta correcta para producción, pero es exagerado cuando solo necesitas un spec rápido para compartir o meter en un Swagger UI. Este conversor hace la mitad de esquema del trabajo en tu navegador — pegas el .proto, copias el YAML, ya tienes components OpenAPI válidos.
La salida es un documento OpenAPI 3.1.0 mínimo pero válido, con un paths: {} vacío y una entrada por cada message o enum de Protobuf en components.schemas. Elegimos OpenAPI 3.1 específicamente porque su modelo de datos se alinea con JSON Schema 2020-12 — esa es la versión donde formatos como int64, date-time y duration son ciudadanos de primera clase y donde $ref puede ir junto a otras keywords sin los hacks de reescritura de la 3.0.
El mapeo de tipos sigue el mapeo JSON de proto3: los enteros de 32 bits pasan a type: integer, format: int32, los de 64 bits a type: string, format: int64 con un patrón numérico (porque los números JSON por encima de 2^53 pierden precisión), repeated T se vuelve un array, map<K, V> se vuelve un objeto con additionalProperties y los nombres de campo se mantienen en snake_case para que el esquema coincida con lo que tu servidor realmente serializa. Los enums se emiten como type: string con una lista enum de nombres de valores — igual que en el JSON de proto3. El conversor corre íntegro en tu navegador; nada de tu esquema sale de la página.
Cómo usarla
Tres pasos. La salida es un documento YAML que puedes meter en un Swagger UI o fusionar con un spec existente.
Pega tu esquema .proto
Suelta el esquema en el editor de la izquierda. syntax = "proto3"; arriba está bien pero es opcional. El parser maneja bloques message anidados, declaraciones enum, oneof, map<K, V> y opciones de campo. Las sentencias import entre archivos se reconocen pero se omiten — pega los tipos importados en línea si tus esquemas se referencian entre sí.
Los nombres de campo se mantienen en snake_case en la salida, coincidiendo con el comportamiento por defecto del encoder JSON de proto3. Si tu gateway está configurado para nombres JSON en camelCase, haz buscar-reemplazar en la salida o cambia el ajuste del gateway.
Lee la salida OpenAPI
A la derecha: un documento YAML con openapi: 3.1.0, un bloque info, un paths: {} vacío y tus messages y enums bajo components.schemas. Las referencias a messages anidados usan $ref: '#/components/schemas/MessageName' contra el nombre hoja, así que las referencias planas funcionan incluso cuando tu .proto declara tipos anidados.
Engánchalo
Suelta el archivo en una instancia de Swagger UI o Redoc para ver cómo se renderizan los esquemas. Para convertirlo en un spec completo, añade entradas reales de paths apuntando a tus rutas de grpc-gateway (o escríbelas a mano) — referéncialas con $ref a #/components/schemas/Order y listo.
Cuándo te ahorra tiempo de verdad
Compartir un esquema con un equipo de frontend o partner
Un equipo de frontend está consumiendo tu servicio transcodificado de gRPC. Te piden un doc OpenAPI para enchufarlo en su generador de tipos o explorador de API. Pega el .proto, copia el YAML, envíalo. Reciben el esquema en un formato que su tooling ya entiende.
Arrancar el spec de una nueva API HTTP transcodificada
Estás levantando un nuevo servicio que correrá tanto como gRPC como HTTP vía grpc-gateway con buf. La sección components/schemas es mecánica — genérala con esta herramienta y luego escribe a mano los paths con las plantillas de ruta correctas. Más rápido que montarlo todo a mano.
Mantener un Swagger UI en sincronía con cambios en .proto
Tu equipo usa Swagger UI para el doc de API legible por humanos, pero la fuente de verdad vive en archivos .proto. Un compañero de backend añade shipping_address a Order; regeneras la sección de schemas aquí, la pegas de vuelta en el spec, lanzas la actualización del doc.
Verificar la salida del codegen
Ejecutaste protoc-gen-openapiv2 como parte de tu build y obtuviste un YAML de 4000 líneas. Para verificar que un message concreto tiene la forma correcta, pega solo ese archivo .proto aquí y compara. Referencia rápida de cómo debería verse un mapeo OpenAPI 3.1 limpio.
Preguntas comunes
¿Por qué OpenAPI 3.1 y no 3.0?
OpenAPI 3.1 alinea su modelo de datos con JSON Schema 2020-12, lo que significa que formatos como int64, date-time y duration están bien definidos y puedes poner $ref junto a otras keywords sin los workarounds incómodos que necesitaba la 3.0. La mayoría del tooling moderno (Redoc, Swagger UI 5, Stoplight, Spectral) habla 3.1 sin problemas. Si realmente necesitas salida 3.0 para tooling antiguo, cambia openapi: 3.1.0 arriba del documento — el resto es lo bastante compatible para que normalmente siga validando.
¿Por qué int64 se emite como string y no como número?
Los números JSON son IEEE-754 doubles en la práctica — pierden precisión por encima de 2^53. El mapeo JSON oficial de proto3 dice que int64, uint64, fixed64, sfixed64 y sint64 deben codificarse como strings JSON. Por eso el esquema OpenAPI usa type: string, format: int64, pattern: "^-?[0-9]+$" para coincidir con lo que el servidor realmente envía. Si quieres asumir valores pequeños y usar type: integer, haz buscar-reemplazar en la salida.
¿Por qué paths está vacío?
Los archivos .proto describen messages y servicios, no rutas HTTP. La transcodificación HTTP (path, method, query, body) se configura aparte — normalmente con anotaciones google.api.http u opciones de grpc-gateway. No las parseamos, así que dejamos paths: {} para que las rellenes tú. La parte components/schemas es la mitad reusable y mecánica — eso es lo que te da esta herramienta.
¿Por qué los nombres de campo están en snake_case?
Porque eso es lo que codifica por defecto el JSON de proto3. order_id en el .proto se serializa como "order_id" en el formato JSON salvo que actives la opción camelCase (preserve_proto_field_names en algunos encoders, o el flag del lado del gateway). Mantener el esquema OpenAPI en snake_case significa que coincide con el JSON que tu servidor realmente envía. Si tu stack usa camelCase, pasa la salida por un buscar-reemplazar.
¿Cómo se manejan los messages anidados?
Cada message Protobuf se vuelve una entrada de nivel superior bajo components.schemas indexada por su nombre hoja (Address, no commerce.v1.Address). Las referencias usan $ref: '#/components/schemas/Address'. Si dos messages tienen el mismo nombre hoja en paquetes distintos, el segundo sobrescribirá al primero — sepáralos en documentos distintos o renombra en el .proto.
¿Entiende los well-known types de google.protobuf?
Algunos. google.protobuf.Timestamp se renderiza como type: string, format: date-time; Duration como type: string, format: duration; Empty como un objeto vacío; Any como un objeto genérico; Value como {} (cualquier valor JSON). Para otros well-known types de Google, el conversor emite actualmente un $ref al nombre hoja — puedes definir esos esquemas tú mismo o sustituir las referencias por el tipo primitivo correcto.
Herramientas relacionadas
Si trabajas con Protobuf y OpenAPI/JSON Schema, estas combinan bien: