microsoft / microsoft/typespec

[Feature Request] [protobuf] Support schematized declaration options.

Open
#4,090 3 comments 7 reactions 0 assignees View on GitHub
emitter:protobuf feature triaged:core
Dominant language
Java
Stars
5.9k
Forks
394
Avg merge
1d 23h
Merged PRs (30d)
104

Description

Protobuf has a very comprehensive system for declaring options that can appear on declarations. Supporting these options in some capacity is essential for supporting several Protobuf usecases. For example, there are options in the `google.api` package that control how gRPC is transcoded to HTTP:

```proto3
service Messaging {
rpc GetMessage(GetMessageRequest) returns Message {
option (google.api.http).get = "/v1/messages/{message_id}/{sub.subfield}";
}
}
```

They can also be compound message value expressions, like this:

```proto3
service MyService {
rpc HelloWorld(HelloWorldRequest) returns HelloWorldResponse {
option (google.api.http) = {
get: "/v1/hello"
body: "greeting"
additional_bindings {
get: "/hello"
}
}
}
}
```

Currently, we support some options at the package level only (since we don't support emitting a package to multiple files, we don't distinguish between file-level and package-file-level options), and they are stringly-typed. These options are tricky for a few reasons:

1. The schemas for options are often declared on the protobuf side. So, the `google.api.http`option schema is enabled by a definition of a message called `HttpRule` in `google/api/http.proto` and is allowed on method declarations by an `extends MethodOptions` declaration in `google/api/annotations.proto`.
2. The option schemas often make use of `oneof` declarations extensively. See https://github.com/microsoft/typespec/issues/1854.
- `oneof` values in protocol buffer data are fundamentally tagged by field index, but union values in TypeSpec are not tagged.
3. Options have their own, separate configuration annotations that look like this:

```tsp
extend google.protobuf.FileOptions {
// Specifies an option of type int32, valid on files, with field index 1234 that has "source retention" i.e. is not part of the runtime descriptor pool.
optional int32 source_retention_option = 1234
[retention = RETENTION_SOURCE];
}
```

Allowing a raw, grammatical options annotation like `@Protobuf.methodOption("(google.api.http).get = \"/hello\"")` could work as a stopgap without allowing the declaration of new options within TypeSpec, since the most common use case is probably to reference options from Google's library or some other extern source.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.