Skip to content

Protobuf schemas in AsyncAPI

A Protocol Buffers message can be an AsyncAPI payload. Wrap the .proto source in a Multi Format Schema Object with schemaFormat: application/vnd.google.protobuf;version=3 (or version=2 for proto2), and put the source text in schema.

Unlike Avro, the schema is a string: the content of a .proto file, not a JSON or YAML object.

asyncapi: 3.0.0
info:
title: Orders
version: 1.0.0
channels:
orderPlaced:
address: orders.placed
messages:
orderPlaced:
$ref: '#/components/messages/orderPlaced'
operations:
onOrderPlaced:
action: receive
channel:
$ref: '#/channels/orderPlaced'
components:
messages:
orderPlaced:
contentType: application/x-protobuf
payload:
schemaFormat: application/vnd.google.protobuf;version=3
schema: |
syntax = "proto3";
package example.orders;
message OrderPlaced {
string order_id = 1;
string customer_id = 2;
repeated LineItem items = 3;
int64 placed_at = 4; // Unix epoch, milliseconds
}
message LineItem {
string sku = 1;
int32 quantity = 2;
}

When the source holds several messages, the payload is the one no other message uses as a field type: here OrderPlaced, because LineItem is a field of it. If more than one message qualifies, mark the payload with a // @RootNode comment, or parsing fails. Leading comments become descriptions.

schemaFormat belongs to the message, and the .proto text goes in payload:

asyncapi: 2.6.0
info:
title: Orders
version: 1.0.0
channels:
orders.placed:
subscribe:
message:
schemaFormat: application/vnd.google.protobuf;version=3
contentType: application/x-protobuf
payload: |
syntax = "proto3";
message OrderPlaced {
string order_id = 1;
}

AsyncAPI tools must understand JSON Schema and AsyncAPI schemas; every other format is a plugin. Protobuf support lives in @asyncapi/protobuf-schema-parser. AsyncAPI CLI and Studio include it. If another validator or generator reports that application/vnd.google.protobuf is unsupported, it runs the parser without that plugin. With the JavaScript parser, register it yourself:

import { Parser } from '@asyncapi/parser'
import { ProtoBuffSchemaParser } from '@asyncapi/protobuf-schema-parser'
const parser = new Parser()
parser.registerSchemaParser(ProtoBuffSchemaParser())
const { document, diagnostics } = await parser.parse(asyncapiYaml)

JSON Schema validators that only check the document’s structure, such as the registry schemas, accept any string in schema for Protobuf; they don’t compile it.

Questions

Can I reference a .proto file instead of inlining it?

Not with the AsyncAPI Protobuf parser: it supports neither $ref to a .proto file nor import, except the bundled google/protobuf/*, google/type/* and validation definitions. Inline the source; many teams generate the inline text from their .proto files at build time.

Which contentType should Protobuf messages have?

application/x-protobuf and application/protobuf are both in use. Pick the one your producers set in message headers and use it consistently.

Does AsyncAPI describe gRPC services?

Not directly. AsyncAPI describes message-driven APIs: channels, operations and messages. It can describe Protobuf messages flowing through Kafka, MQTT, NATS or WebSocket channels; gRPC services are described by their .proto service definitions.