Another advantage of OpenAPI is that you can write your specifications using Rust types (as we do at Oxide with Dropshot: https://docs.rs/dropshot)
edit: Apparently protobuf 3 does have oneof: https://protobuf.dev/programming-guides/proto3/#oneof. They look like they solve the problem but I can't vouch for it, and they appear to have some edge cases ("only the last member seen is used in the parsed message"). Thrift doesn't appear to, still.
And I do think being able to write the spec using Rust types is really nice -- you still get an OpenAPI document as an artifact, and (for external users) you get wide client compatibility.
We actually have a plan for supporting multiple versions, and conversions between the corresponding types, using Dropshot as the place where that's coordinated.
There's a required top-level parameter called version. As you are writing the document, it's in your face.
gRPC requires brittle compilation of the protobuf definitions that has impacted every marshalling/serialization protocol for remote procedure calls since XDR.
Whether you like it or not, HTTP/JSON are the lingua franca of the internet (at least the API side of things). Protobuf is good if you are in control of both sides of the API, less so if you are just the server. It also is much less self-documenting than JSON Schema/OpenAPI.
Interacting with the API is very simple, for example:
const resp = await gameEventClient.getRecentAnnotatedGames({
limit: annotatedPageSize,
offset: recentAnnotatedGamesOffset,
});
setRecentAnnotatedGames(resp.games);
These function calls are typed and a lot of the code is auto-generated from the .proto spec (i.e. above the gameEventClient and getRecentAnnotatedGames are auto-generated code). On the server side the code is also obviously auto-generated. It all works seamlessly. Even the documentation for the API can be auto-generated. See for example:https://buf.build/domino14/liwords
The above documentation was auto-generated from my protobuf files. This project uses ConnectRPC on the backend and on the front-end SPA. To me it seems so much simpler and better than the way I've seen people use OpenAPI - where many people seem to create the code _before_ creating the spec. I actually haven't found a good Go generator of stub code from an OpenAPI spec. With ConnectRPC it just works, it's simple, easy, fast, etc. It's easy to add interceptors to do things like parse the http request for an Auth or Cookie header and then insert the user ID etc back into the context for the different service functions to handle whatever needs to be done with the authenticated user.
I could ask the same question - what am I missing?
> "It's much easier to use the API with JSON + a web browser, but the protobuf option is still available..."
... which sort of underscores my perspective (which is admittedly strongly biased towards / empathetic with the API consumer side).
[meta: IMHO this is an exemplary HN interaction; instead of shouting past each other, we shared very different points of view, and one of us learned something potentially useful.]
Any idea how monstrous migrating from gRPC to ConnectRPC might be, on the backend?
https://connectrpc.com/docs/go/grpc-compatibility/
It might not be super simple. Good interaction, I agree :)
TLDR: there should be no migration cost.