|
|
|
# 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
|
|
|
|
|
|
|
|
In addition, the following conventions should be followed:
|
|
|
|
|
|
|
|
* For protos that are [frozen](https://www.envoyproxy.io/docs/envoy/latest/configuration/overview/v2_overview#status),
|
|
|
|
the following guidelines are followed:
|
|
|
|
|
|
|
|
* Fields should not be renumbered or have their types changed. This is standard proto development
|
|
|
|
procedure.
|
|
|
|
* If fields are deleted, the following syntax should be put in their place:
|
|
|
|
|
|
|
|
```proto
|
|
|
|
reserved <field index>;
|
|
|
|
```
|
|
|
|
|
|
|
|
E.g.,
|
|
|
|
|
|
|
|
```proto
|
|
|
|
reserved 15;
|
|
|
|
```
|
|
|
|
|
|
|
|
* Renaming of fields or package namespaces for a proto must not occur. This is inherently dangerous, since:
|
|
|
|
* Fields renames break wire compatibility. This is stricter than standard proto development procedure
|
|
|
|
in the sense that it does not break binary wire format. However, it **does** break loading
|
|
|
|
of YAML/JSON into protos as well as text protos. Since we consider YAML/JSON to be first class
|
|
|
|
inputs, we must not change field names.
|
|
|
|
|
|
|
|
* For service definitions, the gRPC endpoint URL is inferred from package
|
|
|
|
namespace, so this will break client/server communication.
|
|
|
|
|
|
|
|
* For a message embedded in an `Any` object, the type URL, which the package
|
|
|
|
namespace is a part of, may be used by Envoy or other API consuming code.
|
|
|
|
Currently, this applies to the top-level resources embedded in
|
|
|
|
`DiscoveryResponse` objects, e.g. `Cluster`, `Listener`, etc.
|
|
|
|
|
|
|
|
* Consuming code will break and require source change to match the changes.
|
|
|
|
|
|
|
|
* Non-frozen fields should be tagged with `[#not-implemented-hide:]`, `[#not-implemented-warn:]`,
|
|
|
|
`[#proto-status: draft]` or `[#proto-status: experimental]`.
|
|
|
|
|
|
|
|
* Protos for configs and services that are not implemented immediately in
|
|
|
|
Envoy, or are under active design and development should be versioned
|
|
|
|
"v2alpha". If several iterations of the alpha API are expected, then versions
|
|
|
|
"v2alpha1", "v2alpha2", and so on are preferred. Alpha-versioned protos are
|
|
|
|
considered experimental and are not required to preserve compatibility.
|
|
|
|
|
|
|
|
* 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.
|
|
|
|
|
|
|
|
* 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. For large protos, place a comment
|
|
|
|
at the top that specifies the next free field number. E.g.,
|
|
|
|
|
|
|
|
```
|
|
|
|
// [#comment:next free field: 28]
|
|
|
|
```
|
|
|
|
|
|
|
|
* The [Breaking Change
|
|
|
|
Policy](https://github.com/envoyproxy/envoy/blob/master/CONTRIBUTING.md#breaking-change-policy) describes
|
|
|
|
API versioning, deprecation and compatibility.
|
|
|
|
|
|
|
|
## Package organization
|
|
|
|
|
|
|
|
API definitions are layered hierarchically in packages from top-to-bottom:
|
|
|
|
|
|
|
|
- `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.
|
|
|
|
|
|
|
|
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`.
|