# 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 = ""]` to denote that the field will be renamed to a given name in the next API major version. * `[(udpa.annotations.field_migrate).oneof_promotion = ""]` 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 = "";` 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 = "";` to denote the resource type for an xDS service definition. ### File level * `option (udpa.annotations.file_migrate).move_to_package = "";` 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.