Skip to content

Commit d356110

Browse files
authored
Add docs explaining generated code and its API (#39)
Motivation: Users should be able to understand how the generated code is structured and how it may change over time. Modifications: Add two docs: 1. Explain the structure of the generate code and how to navigate it. 2. Explain how the generated code may change and hot to ensure it doesn't cause API breakages. Result: Better docs
1 parent 219783a commit d356110

File tree

3 files changed

+223
-0
lines changed

3 files changed

+223
-0
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# API stability of generated code
2+
3+
Understand the impact of changes you make to your Protocol Buffers files on the
4+
generated Swift code.
5+
6+
## Overview
7+
8+
The API of the generated code depends on three factors:
9+
10+
- The contents of the source `.proto` file.
11+
- The options you use when generating the code.
12+
- The code generator (the `protoc-gen-grpc-swift` plugin for `protoc`).
13+
14+
While this document applies specifically to the gRPC code generated and *not*
15+
code for messages used as inputs and outputs of each method, the concepts still
16+
broadly apply.
17+
18+
Some of the concepts used in this document are described in more detail in
19+
<doc:Understanding-the-generated-code>.
20+
21+
## The source .proto file
22+
23+
The source `.proto` file defines the API of your service. You'll likely provide
24+
it to users so that they can generate clients from it. In order to maintain API
25+
stability for your service and for clients you must adhere to the following
26+
rules:
27+
28+
1. You mustn't change the `package` the service is defined in.
29+
2. You mustn't change or add the `swift_prefix` option.
30+
3. You mustn't remove or change the name of any services in your `.proto` file.
31+
4. You mustn't remove or change the name of any RPCs in your `.proto` file.
32+
5. You mustn't change the message types used by any RPCs in your `.proto` file.
33+
34+
Failure to follow these will result in changes in the generated code which can
35+
result in build failures for users.
36+
37+
Whilst this sounds restrictive you may do the following:
38+
39+
1. You may add a new RPC to an existing service in your `.proto` file.
40+
2. You may add a new service to your `.proto` file (however it is recommended
41+
that you define a single service per `.proto` file).
42+
43+
## The options you use for generating code
44+
45+
Code you generate into your Swift Package becomes part of the API of your
46+
package. You must therefore ensure that downstream users of your package aren't
47+
impacted by the options you use when generating code.
48+
49+
By default code is generated at the `internal` access level and therefore not
50+
part of the public API. You must explicitly opt in to generating code at the
51+
`public` access level. If you do this then you must be aware that changing what
52+
is generated (clients, servers) affects the public API, as does the access level
53+
of the generated code.
54+
55+
If you need to validate whether your API has changed you can use tools like
56+
Swift Package Manager's API breakage diagnostic (`swift package
57+
diagnose-api-breaking-changes`.) In general you should prefer providing users
58+
with the service's `.proto` file so that they can generate clients, or provide a
59+
library which wraps the client to hide the API of the generated code.
60+
61+
## The code generator
62+
63+
The gRPC Swift maintainers may need to evolve the generated code over time. This
64+
will be done in a source-compatible way.
65+
66+
If APIs are no longer suitable then they may be deprecated in favour of new
67+
ones. Within a major version of the package existing API won't be removed
68+
and deprecated APIs will continue to function.
69+
70+
If the generator introduces new ways to generate code which are incompatible
71+
with the previously generated code then they will require explicit opt-in via an
72+
option.
73+
74+
As gRPC Swift is developed the generated code may need to rely on newer
75+
functionality from its runtime counterparts (`GRPCCore` and `GRPCProtobuf`).
76+
This means that you should use the versions of `protoc-gen-grpc-swift` and
77+
`protoc-gen-swift` resolved with your package rather than getting them from an
78+
out-of-band (such as `homebrew`).
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Understanding the generated code
2+
3+
Understand what code is generated by `protoc-gen-grpc-swift` from a `.proto`
4+
file and how to use it.
5+
6+
## Overview
7+
8+
The gRPC Swift Protobuf package provides a plugin to the Protocol Buffers
9+
Compiler (`protoc`) called `protoc-gen-grpc-swift`. The plugin is responsible
10+
for generating the gRPC specific code for services defined in a `.proto` file.
11+
12+
### Package namespace
13+
14+
Most `.proto` files contain a `package` directive near the start of the file
15+
describing the namespace it belongs to. Here's an example:
16+
17+
```proto
18+
package foo.bar.v1;
19+
```
20+
21+
The package name "foo.bar.v1" is important as it is used as a prefix for
22+
generated types. The default behaviour is to replace periods with underscores
23+
and to capitalize each word and add a trailing underscore. For this package the
24+
prefix is "Foo\_Bar\_V1\_". If you don't declare a package then the prefix will be
25+
the empty string.
26+
27+
You can override the prefix by setting the `swift_prefix` option:
28+
29+
```proto
30+
option swift_prefix = "FooBarV1";
31+
32+
package foo.bar.v1;
33+
```
34+
35+
The prefix for types in this file would be "FooBarV1" instead of "Foo\_Bar\_V1\_".
36+
37+
### Service namespace
38+
39+
For each service declared in your `.proto` file, gRPC will generate a caseless
40+
`enum` which is a namespace holding the generated protocols and types. The name
41+
of this `enum` is `{PREFIX}{SERVICE}` where `{PREFIX}` is as described in the
42+
previous section and `{SERVICE}` is the name of the service as declared in the
43+
`.proto` file.
44+
45+
As an example the following definition creates a service namespace `enum` called
46+
`Foo_Bar_V1_BazService` (the `{PREFIX}` is "Foo_Bar_V1_" and `{SERVICE}` is
47+
"BazService"):
48+
49+
```proto
50+
package foo.bar.v1;
51+
52+
service BazService {
53+
// ...
54+
}
55+
```
56+
57+
Code generated for each service falls into three categories:
58+
59+
1. Service metadata,
60+
2. Service code, and
61+
3. Client code.
62+
63+
#### Service metadata
64+
65+
gRPC generates metadata for each service including a descriptor identifying the
66+
fully qualified name of the service and information about each method in the
67+
service. You likely won't need to interact directly with this information but
68+
it's available should you need to.
69+
70+
#### Service code
71+
72+
Within a service namespace gRPC generates three service protocols:
73+
74+
1. `StreamingServiceProtocol`,
75+
2. `ServiceProtocol`, and
76+
3. `SimpleServiceProtocol`.
77+
78+
The full name of each protocol includes the service namespace.
79+
80+
> Example:
81+
>
82+
> For the `BazService` in the `foo.bar.v1` package the protocols would be:
83+
>
84+
> - `Foo_Bar_V1_BazService.StreamingServiceProtocol`,
85+
> - `Foo_Bar_V1_BazService.ServiceProtocol`, and
86+
> - `Foo_Bar_V1_BazService.SimpleServiceProtocol`.
87+
88+
Each of these protocols mirror the `service` defined in your `.proto` file with
89+
one requirement per RPC. To implement your service you must implement one of
90+
these protocols.
91+
92+
The protocols form a hierarchy with `StreamingServiceProtocol` at the bottom and
93+
`SimpleServiceProtocol` at the top. `ServiceProtocol` refines
94+
`StreamingServiceProtocol`, and `SimpleServiceProtocol` refines
95+
`ServiceProtocol` (and `StreamingServiceProtocol` in turn).
96+
97+
The `StreamingServiceProtocol` implements each RPC as if it were a bidirectional
98+
streaming RPC. This gives you the most flexibility at the cost of a harder to
99+
implement API. It also puts the responsibility on you to ensure that each RPC
100+
sends and receives the correct number of messages.
101+
102+
The `ServiceProtocol` enforces that the correct number of messages are sent and
103+
received via its API. It also allows you to read request metadata and send both
104+
initial and trailing metadata. The request and response types for these
105+
requirements are in terms of `ServerRequest` and `ServerResponse`.
106+
107+
The `SimpleServiceProtocol` also enforces the correct number of messages are
108+
sent and received via its API. However, it isn't defined in terms of
109+
`ServerRequest` or `ServerResponse` so it doesn't allow you access metadata.
110+
This limitation allows it to have the simplest API and is preferred if you don't
111+
need access to metadata.
112+
113+
| Protocol | Enforces number of messages | Access to metadata
114+
|----------------------------|-----------------------------|-------------------
115+
| `StreamingServiceProtocol` | ✗ | ✓
116+
| `ServiceProtocol` | ✓ | ✓
117+
| `SimpleServiceProtocol` | ✓ | ✗
118+
119+
#### Client code
120+
121+
gRPC generates two types for the client within a service namespace:
122+
123+
1. `ClientProtocol`, and
124+
2. `Client`.
125+
126+
Like the service code, the full name includes the namespace.
127+
128+
> Example:
129+
>
130+
> For the `BazService` in the `foo.bar.v1` package the client types would be:
131+
>
132+
> - `Foo_Bar_V1_BazService.ClientProtocol`, and
133+
> - `Foo_Bar_V1_BazService.Client`.
134+
135+
The `ClientProtocol` defines one requirement for each RPC in terms of
136+
`ClientRequest` and `ClientResponse`. You don't need to implement the protocol
137+
as `Client` provides a concrete implementation.
138+
139+
gRPC also generates extensions on `ClientProtocol` to provide more ergonomic
140+
APIs. These include versions which provide default arguments for various
141+
parameters (like the message serializer and deserializers; call options and
142+
response handler) and versions which don't use `ClientRequest` and
143+
`ClientResponse` directly.

Sources/GRPCProtobuf/Documentation.docc/Documentation.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ This package provides three products:
2121

2222
- <doc:Installing-protoc>
2323
- <doc:Generating-stubs>
24+
- <doc:API-stability-of-generated-code>
25+
- <doc:Understanding-the-generated-code>
2426

2527
### Serialization
2628

0 commit comments

Comments
 (0)