Conversor de Protobuf para JSON Schema
Cole um esquema .proto. Receba um documento JSON Schema 2020-12 com uma entrada $defs por message e enum, pronto para Ajv ou qualquer validador moderno.
Entrada (esquema .proto)
Saída (JSON Schema)
O que esta ferramenta faz
Você tem um esquema Protocol Buffers e um serviço que recebe JSON — talvez um handler de webhook, talvez um gateway gRPC com HTTP transcoding, talvez um API gateway que valida a request antes dela chegar ao seu código. Você quer um documento JSON Schema que espelhe o proto para validar payloads de entrada, gerar fragmentos de OpenAPI, ou alimentar prompts de saída estruturada. Este conversor faz isso no seu navegador — cole o .proto, copie o JSON Schema, jogue na config do seu validador.
A saída é JSON Schema draft 2020-12 — o draft atual, suportado por todo validador moderno incluindo o Ajv. Cada message vira uma entrada sob $defs com type: "object" e um mapa properties. Cada enum vira uma entrada de $defs com type: "string" e os nomes de valor listados sob enum — alinhado com a forma como proto3 serializa enums por nome em JSON. Referências de campo resolvem via $ref: "#/$defs/MessageName" usando o nome folha, então tipos aninhados ficam legíveis.
O mapeamento de tipos segue a spec de mapeamento proto3 para JSON. string/bool mapeiam direto. Ints de 32 bits viram type: "integer" com format: "int32"; unsigned 32 bits adicionam minimum: 0. Ints de 64 bits viram type: "string" com format: "int64" e um pattern numérico, porque JSON Numbers perdem precisão acima de 2^53 e proto3 codifica inteiros de 64 bits como strings entre aspas no wire. bytes vira string com contentEncoding: "base64". Tipos well-known como google.protobuf.Timestamp mapeiam para format: "date-time" conforme a RFC 3339. A conversão roda inteiramente no seu navegador — seu esquema não sai da página.
Como usar
Três passos. A saída é um único documento JSON Schema que você pode passar direto para um validador.
Cole seu esquema .proto
Solte o esquema no editor da esquerda. syntax = "proto3"; no topo é OK mas opcional. O parser lida com blocos message aninhados, declarações enum, oneof, map<K, V> e opções de campo. Diretivas import são reconhecidas mas puladas — cole os tipos importados inline se precisar.
Nomes de campo permanecem em snake_case (alinhado ao que o encoder JSON proto3 emite por padrão — sem transformação). Se seu cliente seta preserve_proto_field_names = false, troque as chaves de propriedade para camelCase manualmente.
Leia o esquema
À direita: um documento JSON Schema 2020-12 com $id, title, um $ref de nível superior apontando para a última message raiz declarada e um bloco $defs contendo cada message e enum do arquivo. Cada message vira um schema de objeto com um mapa properties; cada enum vira um schema de string com os nomes de valor. Leia o guia Understanding JSON Schema se precisar revisar a semântica de $ref ou $defs.
Pluga num validador
Salve a saída como schema.json, carregue no Ajv (Node) ou jsonschema (Python) ou no validador que sua stack usa, depois rode contra o JSON que sua gRPC-gateway ou webhook recebe. Discrepâncias aparecem como caminhos de erro legíveis tipo /items/0/sku must be string. O mesmo schema pode também alimentar definições de componentes OpenAPI 3.1 ou prompts de saída estruturada para um LLM.
Quando isso realmente economiza tempo
Validar webhooks definidos em proto
Sua equipe usa Protobuf como fonte de verdade para um evento OrderShipped, mas o receptor real do webhook pega JSON — não tem runtime de proto no receptor. Cole o .proto, jogue o JSON Schema no Ajv e rejeite payloads malformados na borda antes deles chegarem na lógica de negócio. Um SKU-101 com quantity faltando nunca chega no banco.
Construir OpenAPI 3.1 a partir de esquemas gRPC
Você está escrevendo specs OpenAPI 3.1 para uma gRPC-gateway. OpenAPI 3.1 é compatível com JSON Schema 2020-12, então o bloco $defs daqui cai direto sob components.schemas depois de uma pequena renomeação. Sem instalar o plugin protoc-gen-openapi, sem montar Buf CLI — só colar, editar, comitar.
Saídas estruturadas de LLM a partir de um proto
Você quer que OpenAI ou Anthropic retornem um objeto Order tipado que combine com seu .proto existente. Cole o esquema, pegue a entrada $defs/Order e passe como o JSON Schema do response_format. O modelo agora produz saída que faz round-trip pelo seu serviço gRPC sem coerção manual.
Revisar uma mudança de API Protobuf
Um colega de backend adicionou dois campos em Address e renomeou um valor de enum. Você quer ver como isso afeta o JSON Schema que sua gateway usa sem rodar a pipeline completa de codegen. Cole o novo .proto, faça diff do schema contra sua cópia comitada, deixe um comentário de revisão focado no PR.
Perguntas comuns
Meu esquema é enviado para algum lugar?
Não. O parser e o emissor de JSON Schema rodam inteiramente no seu navegador como JavaScript. Abra o DevTools e olhe a aba Network enquanto cola — zero requests. Útil quando seu esquema inclui paths de package internos, nomes de tipo ou qualquer coisa que você não queira entregar a um serviço terceiro.
Qual draft de JSON Schema a saída tem como alvo?
Draft 2020-12, o draft publicado atual. O URI $schema em todo documento de saída é https://json-schema.org/draft/2020-12/schema. Veja as notas de release 2020-12 para o que mudou desde 2019-09. Todo validador ativamente mantido (Ajv 8+, jsonschema 4+ para Python, NJsonSchema, Justify para Java) suporta 2020-12 por padrão.
Por que campos int64 são strings, não integers?
Porque é o que a spec de mapeamento proto3 para JSON diz, e ela está certa. JSON Numbers são doubles IEEE-754, que perdem precisão acima de 2^53. Um int64 de verdade pode carregar valores muito além desse teto — IDs de pedido, timestamps em nanos, saldos de ledger — então proto3 codifica inteiros de 64 bits como strings JSON entre aspas. O schema reflete isso com type: "string", format: "int64" e um pattern numérico para que um validador ainda rejeite "abc". Se seu servidor entrega ints de 64 bits como JSON Numbers crus (algumas gateways legadas fazem isso), troque essas entradas para { "type": "integer" } manualmente.
Por que enums são strings, não integers?
Mesmo motivo — é a codificação JSON padrão do proto3. Enums serializam como o nome do valor ("ORDER_STATUS_PAID") em vez do número inteiro do wire (2). Isso deixa payloads JSON legíveis e o schema mais simples. Os números inteiros não estão no JSON Schema porque são uma preocupação de wire format, não de validação. Se você tem um encoder não padrão configurado para emitir ints, troque type: "string" por type: "integer" na entrada do enum.
Como ele lida com map<K, V>?
Renderiza como { "type": "object", "additionalProperties": <V-schema> }. Chaves de objeto JSON são sempre strings, então um map proto com chave não-string (ex.: map<int32, string>) ganha uma nota descritiva explicando que as chaves em runtime serão coercidas para string. O schema do valor segue as mesmas regras de mapeamento de tipo de um campo regular.
Os campos são marcados como required?
Não — campos proto3 sempre têm um default no wire format e estão sempre presentes na saída JSON (com defaults vazios como "", 0, false, [], {}), então o schema não lista nada sob required. Se você realmente quer que um campo seja required no momento da validação, adicione-o num array required na message pai manualmente. Campos optional de proto3 e oneof também não são forçados como oneOf na saída — essas são semânticas de runtime que o JSON Schema não consegue expressar plenamente sem anotações extras.
Como messages aninhadas são referenciadas?
Cada message e enum é içada para um bloco $defs plano indexado pelo nome folha. Referências de campo passam por $ref: "#/$defs/MessageName". Achatar mantém o documento compacto e faz com que tipos aninhados duas vezes não sejam duplicados. Se duas messages em packages diferentes compartilham um nome folha, o conversor mantém a primeira definição — separe nomes em conflito antes de colar se isso importa.
Posso plugar isso direto no Ajv?
Sim. ajv.compile(schema) na saída funciona out-of-the-box uma vez que o Ajv esteja configurado para draft 2020-12 (new Ajv2020() de ajv/dist/2020). As entradas $ref resolvem internamente porque tudo está no mesmo documento. Se quiser validação de format (date-time, duration), adicione ajv-formats junto.
Ferramentas relacionadas
Se você está mexendo com Protobuf, JSON Schema e validação, estas combinam bem: