RPC code generation
I imagine most of you are familiar with RPC client and server codegen patterns.
- Write a interface description, for example OpenAPI or gRPC and Protocol Buffers.
- From those declarative descriptions of the types and functions, generate the stub code for the server.
- From the same declarative descriptions, generate clients that can call the server.
What makes this great is that you can generate a client for whatever languages you like with minimal marginal cost. Those clients stay in sync via the interface description and modulo deployment timing differences, everything is always in sync. The generated code has native types and an SDK in the client language of choice and everything gets serialized the same on the wire, so the server is happy.
dropshot taught me something new
Dropshot is a general-purpose crate for exposing HTTP APIs from a Rust program released by Oxide Computer Company. Notably, Dropshot is OpenAPI compatible, which is where it comes into this story.
Dropshot does not do Step 1 or Step 2 in the above pattern. Instead, Dropshot generates an OpenAPI spec from the server code itself. This is brilliant, because it dodges a few concrete problems and it gets at a deeper essential truth about this pattern: The server code is the authoritative source of the interface description, not the other way around.
Why is this concretely better?
- You no longer have to write an interface description. This is saved work.
- When the interface changes, merging the generated server code with the existing server code is messy. Because there no longer is any generated server code, you get to dodge this error-prone step.
- You benefit from the language's static analysis and compilation checks insteading of having a two-step process of write interface description -> merge generated code into server code.
- You no longer have the extra complexity of code-generation in your dev-workflow for the server.
Why is the server code actually the root of authority?
Unless you have or plan to have multiple implementations of the server using different stacks, there's only ever one implementation of the server.
As long as the server is serving requests, it is axiomatic that the behavior and interface of the server is exactly specified by the server's code. On the other hand, it is possible that the server simply diverges from the interface description. For example, when merging the generated code, human error might cause the divergence. Or it may happen naturally during some refactoring or bugfix even when you weren't trying to change the interface.
However, if you generate the interface description from the server code itself, it is not possible for it to diverge. (A bug in the generation code is possible, but this case is also true for generating the server code.)