You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
9.6 KiB
187 lines
9.6 KiB
# API style guidelines |
|
|
|
Generally follow guidance at https://cloud.google.com/apis/design/, in |
|
particular for proto3 as described at: |
|
|
|
* https://cloud.google.com/apis/design/proto3 |
|
* https://cloud.google.com/apis/design/naming_convention |
|
* https://developers.google.com/protocol-buffers/docs/style |
|
|
|
A key aspect of our API style is maintaining stability by following the [API versioning |
|
guidelines](API_VERSIONING.md). All developers must familiarize themselves with these guidelines, |
|
any PR which makes breaking changes to the API will not be merged. |
|
|
|
In addition, the following conventions should be followed: |
|
|
|
* Every proto directory should have a `README.md` describing its content. See |
|
for example [envoy.service](envoy/service/README.md). |
|
|
|
* The data plane APIs are primarily intended for machine generation and consumption. |
|
It is expected that the management server is responsible for mapping higher |
|
level configuration concepts to concrete API concepts. Similarly, static configuration |
|
fragments may be generated by tools and UIs, etc. The APIs and tools used |
|
to generate xDS configuration are beyond the scope of the definitions in this |
|
repository. |
|
|
|
* Use [wrapped scalar |
|
types](https://github.com/google/protobuf/blob/master/src/google/protobuf/wrappers.proto) |
|
where there is a real need for the field to have a default value that does not |
|
match the proto3 defaults (0/false/""). This should not be done for fields |
|
where the proto3 defaults make sense. All things being equal, pick appropriate |
|
logic, e.g. enable vs. disable for a `bool` field, such that the proto3 |
|
defaults work, but only where this doesn't result in API gymnastics. |
|
|
|
* Use a `[#not-implemented-hide:]` `protodoc` annotation in comments for fields that lack Envoy |
|
implementation. These indicate that the entity is not implemented in Envoy and the entity |
|
should be hidden from the Envoy documentation. |
|
|
|
* Always use plural field names for `repeated` fields, such as `filters`. |
|
|
|
* Due to the fact that we consider JSON/YAML to be first class inputs, we cannot easily change a |
|
a singular field to a repeated field (both due to JSON/YAML array structural differences as well |
|
as singular vs. plural field naming). If there is a reasonable expectation that a field may need |
|
to be repeated in the future, but we don't need it to be repeated right away, consider making it |
|
repeated now but using constraints to enforce a maximum repeated size of 1. E.g.: |
|
|
|
```proto |
|
repeated OutputSink sinks = 1 [(validate.rules).repeated = {min_items: 1, max_items: 1}]; |
|
``` |
|
|
|
* Always use upper camel case names for message types and enum types without embedded |
|
acronyms, such as `HttpRequest`. |
|
|
|
* Prefer `oneof` selections to boolean overloads of fields, for example, prefer: |
|
|
|
```proto |
|
oneof path_specifier { |
|
string simple_path = 1; |
|
string regex_path = 2; |
|
} |
|
``` |
|
|
|
to |
|
|
|
```proto |
|
string path = 1; |
|
bool path_is_regex = 2; |
|
``` |
|
|
|
This is more efficient, extendable and self-describing. |
|
|
|
* The API includes two types for representing [percents](envoy/type/percent.proto). `Percent` is |
|
effectively a double value in the range 0.0-100.0. `FractionalPercent` is an integral fraction |
|
that can be used to create a truncated percentage also in the range 0.0-100.0. In high performance |
|
paths, `FractionalPercent` is preferred as randomness calculations can be performed using integral |
|
modulo and comparison operations only without any floating point conversions. Typically, most |
|
users do not need infinite precision in these paths. |
|
|
|
* For enum types, if one of the enum values is used for most cases, make it the |
|
first enum value with `0` numeric value. Otherwise, define the first enum |
|
value like `TYPE_NAME_UNSPECIFIED = 0`, and treat it as an error. This design |
|
pattern forces developers to explicitly choose the correct enum value for |
|
their use case, and avoid misunderstanding of the default behavior. |
|
|
|
* Proto fields should be sorted logically, not by field number. |
|
|
|
## Package organization |
|
|
|
API definitions are layered hierarchically in packages from top-to-bottom in v2 as following: |
|
|
|
- `envoy.service` contains gRPC definitions of supporting services; |
|
- `envoy.config` contains definitions for service configuration, filter |
|
configuration, and bootstrap; |
|
- `envoy.api.v2` contains definitions for EDS, CDS, RDS, LDS, and top-level |
|
resources such as `Cluster`; |
|
- `envoy.api.v2.endpoint`, `envoy.api.v2.cluster`, `envoy.api.v2.route`, |
|
`envoy.api.v2.listener`, `envoy.api.v2.ratelimit` define sub-messages of the top-level resources; |
|
- `envoy.api.v2.core` and `envoy.api.v2.auth` hold core definitions consumed |
|
throughout the API. |
|
|
|
In Envoy API v3, API definitions are layered hierarchically in packages from top-to-bottom as following: |
|
- `envoy.extensions` contains all definitions for the extensions, the package should match the structure of the `source` directory. |
|
- `envoy.service` contains gRPC definitions of supporting services and top-level messages for the services. |
|
e.g. `envoy.service.route.v3` contains RDS, `envoy.service.listener.v3` contains LDS. |
|
- `envoy.config` contains other definitions for service configuration, bootstrap and some legacy core types. |
|
- `envoy.data` contains data format declaration for data types that Envoy produces. |
|
- `envoy.type` contains common protobuf types such as percent, range and matchers. |
|
|
|
Dependencies are enforced from top-to-bottom using visibility constraints in |
|
the build system to prevent circular dependency formation. Package group |
|
`//envoy/api/v2:friends` selects consumers of the core API package (services and configs) |
|
and is the default visibility for the core API packages. The default visibility |
|
for services and configs should be `//docs` (proto documentation tool). |
|
|
|
Extensions should use the regular hierarchy. For example, configuration for network filters belongs |
|
in a package under `envoy.config.filter.network`. |
|
|
|
## Adding an extension configuration to the API |
|
|
|
Extensions must currently be added as v2 APIs following the [package |
|
organization](#package-organization) above. |
|
To add an extension config to the API, the steps below should be followed: |
|
|
|
1. If this is still WiP and subject to breaking changes, use `vNalpha` instead of `vN` in steps |
|
below. Refer to the [Cache filter config](envoy/config/filter/http/cache/v2alpha/cache.proto) |
|
as an example of `v2alpha`, and the |
|
[Buffer filter config](envoy/config/filter/http/buffer/v2/buffer.proto) as an example of `v2`. |
|
1. Place the v2 extension configuration `.proto` in `api/envoy/config`, e.g. |
|
`api/envoy/config/filter/http/foobar/v2/foobar.proto` together with an initial BUILD file: |
|
``` |
|
load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") |
|
|
|
licenses(["notice"]) # Apache 2 |
|
|
|
api_proto_package( |
|
deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"], |
|
) |
|
``` |
|
1. Add to the v2 extension config proto `import "udpa/annotations/migrate.proto";` |
|
1. Add to the v2 extension config proto a file level `option (udpa.annotations.file_migrate).move_to_package = "envoy.extensions.filters.http.foobar.v3";`. |
|
This places the filter in the correct [v3 package hierarchy](#package-organization). |
|
1. If this is still WiP and subject to breaking changes, import |
|
`udpa/annotations/status.proto` and set `option (udpa.annotations.file_status).work_in_progress = true;`. |
|
1. Add a reference to the v2 extension config in (1) in [api/docs/BUILD](docs/BUILD). |
|
1. Run `./tools/proto_format fix`. This should regenerate the `BUILD` file, |
|
reformat `foobar.proto` as needed and also generate the v3 extension config, |
|
together with shadow API protos. |
|
1. `git add api/ generated_api_shadow/` to add any new files to your Git index. |
|
|
|
## API annotations |
|
|
|
A number of annotations are used in the Envoy APIs to provide additional API |
|
metadata. We describe these annotations below by category. |
|
|
|
### Field level |
|
* `[deprecated = true]` to denote fields that are deprecated in a major version. |
|
These fields are slated for removal at the next major cycle and follow the |
|
[breaking change policy](../CONTRIBUTING.md#breaking-change-policy). |
|
* `[envoy.annotations.disallowed_by_default = true]` to denote fields that have |
|
been disallowed by default as per the [breaking change policy](../CONTRIBUTING.md#breaking-change-policy). |
|
* `[(udpa.annotations.field_migrate).rename = "<new field name>"]` to denote that |
|
the field will be renamed to a given name in the next API major version. |
|
* `[(udpa.annotations.field_migrate).oneof_promotion = "<oneof name>"]` to denote that |
|
the field will be promoted to a given `oneof` in the next API major version. |
|
* `[(udpa.annotations.sensitive) = true]` to denote sensitive fields that |
|
should be redacted in output such as logging or configuration dumps. |
|
* [PGV annotations](https://github.com/envoyproxy/protoc-gen-validate) to denote field |
|
value constraints. |
|
|
|
### Enum value level |
|
* `[(udpa.annotations.enum_value_migrate).rename = "new enum value name"]` to denote that |
|
the enum value will be renamed to a given name in the next API major version. |
|
|
|
### Message level |
|
* `option (udpa.annotations.versioning).previous_message_type = "<message type |
|
name>";` to denote the previous type name for an upgraded message. You should |
|
never have to write these manually, they are generated by `protoxform`. |
|
|
|
### Service level |
|
* `option (envoy.annotations.resource).type = "<resource type name>";` to denote |
|
the resource type for an xDS service definition. |
|
|
|
### File level |
|
* `option (udpa.annotations.file_migrate).move_to_package = "<package name>";` |
|
to denote that in the next major version of the API, the file will be moved to |
|
the given package. This is consumed by `protoxform`. |
|
* `option (udpa.annotations.file_status).work_in_progress = true;` to denote a |
|
file that is still work-in-progress and subject to breaking changes.
|
|
|