Guide
TypeSpec includes a built-in emitter (/protobuf
) that can generate Protocol Buffers specifications from TypeSpec sources. The Protobuf files generated can then be used to create gRPC services or any other tools that are compatible with Protocol Buffers.
Please note: The Protobuf emitter is designed to work with Protocol Buffers 3 (proto3) syntax. Ensure that your workflow (including protoc
version) supports proto3 to make full use of this emitter.
Fundamental Concepts
The Protobuf emitter allows you to write TypeSpec and transform it into corresponding Protocol Buffers for use with systems that support Protobuf (like gRPC). To successfully convert your TypeSpec models and interfaces to Protobuf, they must comply with certain rules and limitations.
Packages
A protobuf package is established by the TypeSpec.Protobuf.package
decorator, which is applied to a TypeSpec namespace. Essentially, a package defines a .proto
file, and all contents within the decorated namespace are emitted into a single file.
Consider the following TypeSpec namespace, which results in a Protobuf file named main.proto
containing the contents of the Test
namespace, converted into Protobuf.
You can specify package names using the optional PackageDetails
argument with the @package
decorator. The following TypeSpec namespace will create a file com/example/test.proto
that includes the line package com.example.test;
:
TypeSpec entities (like models, enums, etc.) are transformed into Protobuf declarations within their closest ancestor that has a package annotation. This means that, unlike in Protobuf, TypeSpec package declarations can be nested as needed.
Messages
TypeSpec models are translated into Protobuf messages. For instance, the following TypeSpec model:
will be transformed into the Protobuf message below:
Models are converted into messages and included in the Protobuf file if they meet any of the following conditions:
- The model is explicitly annotated with the
TypeSpec.Protobuf.message
decorator. - The model is referenced by any service operation (refer to Services below).
- The model is a direct child of a package namespace and every field is annotated with the
TypeSpec.Protobuf.field
decorator.
Field Indices
Protobuf requires manual specification of the offset for each field within a Protobuf message. In TypeSpec, these field indices are specified using the TypeSpec.Protobuf.field
decorator. To be converted into a Protobuf message, all fields within a model must have an attached @field
decorator.
The following TypeSpec model:
will be transformed into the Protobuf message below:
Services
TypeSpec defines a “service” using the TypeSpec.service
decorator, but the Protobuf “service” concept is different and is denoted by the TypeSpec.Protobuf.service
decorator.
When using the Protobuf emitter, a Protobuf service designation is applied to an interface within a package. For example, the following TypeSpec:
will generate the following Protobuf file (named example.proto
):
Operations
Within a service interface, TypeSpec operations are represented as Protobuf service methods. Each operation in the service interface is converted into an equivalent Protobuf method declaration. For instance, the following specification:
Results in the following .proto
file:
Streams
The Protobuf emitter supports the declaration of an operation’s streaming mode using the TypeSpec.Protobuf.stream
decorator. The streaming mode is defined using the StreamMode
enum. An operation can have one of four streaming modes:
-
None
: This is the default mode, indicating that neither the request nor the response are streamed.Example:
rpc Example(In) returns (Out);
-
In
: This mode indicates that the request is streamed, but the response is received synchronously.Example:
rpc Example(stream In) returns (Out);
-
Out
: This mode indicates that the request is sent synchronously, but the response is streamed.Example:
rpc Example(In) returns (stream Out);
-
Duplex
: This mode indicates that both the request and response are streamed.Example:
rpc Example(stream In) returns (stream Out);