Evaluate ConnectRPC over gRPC + webgateway #886

Open
opened 2025-12-29 02:25:16 +01:00 by adam · 10 comments
Owner

Originally created by @kradalby on GitHub (Dec 17, 2024).

We currently use plain gRPC and grpc-gateway (for our http+json) api, it has worked fine, but also there are a couple of drawbacks, and it kind of feels a bit hacky.

One of the drawbacks is that some parts of gRPC is unsupported by grpc-gateway, and it does not support OpenAPI 3.0. oneof is for example not supported https://github.com/juanfont/headscale/issues/2237.

ConnectRPC seem to be a rethinking of this, where the gRPC and the HTTP part is "equally" important. It might be better, it might be worse, they advertise with good client code generators so might be worth a look.

Initial thoughts:

  • Con: This will break current web UIs
  • Pro: they can use a generated client instead of handwriting API
  • Cant see any OpenAPI support, but if their code gen is good, then I dont think that matters
  • "If it aint broke, dont fix it"

I would value peoples views, particularly if you have experience using this.

Originally created by @kradalby on GitHub (Dec 17, 2024). We currently use plain gRPC and grpc-gateway (for our http+json) api, it has worked fine, but also there are a couple of drawbacks, and it kind of feels a bit hacky. One of the drawbacks is that some parts of gRPC is unsupported by grpc-gateway, and it does not support OpenAPI 3.0. `oneof` is for example not supported https://github.com/juanfont/headscale/issues/2237. ConnectRPC seem to be a rethinking of this, where the gRPC and the HTTP part is "equally" important. It might be better, it might be worse, they advertise with good client code generators so might be worth a look. Initial thoughts: - Con: This will break current web UIs - Pro: they can use a generated client instead of handwriting API - Cant see any OpenAPI support, but if their code gen is good, then I dont think that matters - "If it aint broke, dont fix it" I would value peoples views, particularly if you have experience using this.
adam added the questionhelp wantedno-stale-botneeds investigation labels 2025-12-29 02:25:16 +01:00
Author
Owner

@perezd commented on GitHub (Dec 19, 2024):

RE: OpenAPI support, there's a fantastic plugin for this that supports Connect: https://github.com/sudorandom/protoc-gen-connect-openapi?tab=readme-ov-file

If you'd like to chat about the eval w/ the Connect team we're here in Slack: https://buf.build/b/slack

@perezd commented on GitHub (Dec 19, 2024): RE: OpenAPI support, there's a fantastic plugin for this that supports Connect: https://github.com/sudorandom/protoc-gen-connect-openapi?tab=readme-ov-file If you'd like to chat about the eval w/ the Connect team we're here in Slack: https://buf.build/b/slack
Author
Owner

@majst01 commented on GitHub (Dec 20, 2024):

As a long term user of the connectrpc stack since the 0.1 version, i really can say that this was the best improvement of the grpc ecosystem ever. Could only say good things about that. So go for it.

@majst01 commented on GitHub (Dec 20, 2024): As a long term user of the connectrpc stack since the 0.1 version, i really can say that this was the best improvement of the grpc ecosystem ever. Could only say good things about that. So go for it.
Author
Owner

@kradalby commented on GitHub (Aug 10, 2025):

Another contender to using connect and grpc would be to leverage the now stable tailscale v2 api client, and use all the types in it: 9ce246ebbf/devices.go (L70)
Having all the types now that there is one official client makes this a lot easier than previously when they had two clients.

If we implement this as our api, and use the go api client we could theoretically end up with terraform and others support, at least if it doesn't require oauth.

By using the go client in our own cli, we would ensure we have to handle what ever changes comes our way all the time.

@kradalby commented on GitHub (Aug 10, 2025): Another contender to using connect and grpc would be to leverage the now stable tailscale v2 api client, and use all the types in it: https://github.com/tailscale/tailscale-client-go-v2/blob/9ce246ebbf4e72f25327e932a4caf066cc63bb12/devices.go#L70 Having all the types now that there is one official client makes this a lot easier than previously when they had two clients. If we implement this as our api, and use the go api client we could theoretically end up with terraform and others support, at least if it doesn't require oauth. By using the go client in our own cli, we would ensure we have to handle what ever changes comes our way all the time.
Author
Owner

@kradalby commented on GitHub (Sep 9, 2025):

I'm getting more and more keen on the idea in the previous comment, particularly since the gRPC + gateway + tooling is kind of a pain and makes us run the api/grpc part on different ports and other annoyances.

Tailscale's API has a OpenAPI 3.1 spec, while our is stuck on v2 for the foreseeable future. This means that generation of client code should be available for most languages.

The main stakeholders as I see it is the web developers, so while I'm getting more firm that we will move in this direction, or at least to a PoC to test it, I'll tag them so we can have a look at it together:

@routerino @simcu @tale @GoodiesHQ @yellowsink @ich777 @rickli-cloud

@kradalby commented on GitHub (Sep 9, 2025): I'm getting more and more keen on the idea in the previous comment, particularly since the gRPC + gateway + tooling is kind of a pain and makes us run the api/grpc part on different ports and other annoyances. Tailscale's API has a OpenAPI 3.1 spec, while our is stuck on [v2 for the foreseeable future](https://github.com/grpc-ecosystem/grpc-gateway/issues/441). This means that generation of client code should be available for most languages. The main stakeholders as I see it is the web developers, so while I'm getting more firm that we will move in this direction, or at least to a PoC to test it, I'll tag them so we can have a look at it together: @routerino @simcu @tale @GoodiesHQ @yellowsink @ich777 @rickli-cloud
Author
Owner

@tale commented on GitHub (Sep 10, 2025):

I'd be fine with this change assuming it will be in 0.27 or a new major release. Since this will create breaking changes for the API I would also like to see 2 different changes that should hopefully become easier with the switch to connectRPC.

  • The OpenAPI document should be full spec, including the version and all, the missing metadata that is currently not there.
  • API routes need to align with these error codes: https://connectrpc.com/docs/protocol/#error-codes. I've had too many scenarios where the REST API will return a 5xx status code and then have a JSON body with an error that isn't a server error.

Otherwise, I fully support this change and would like the opportunity to test it early and utilize the breaking change to try and refine the API design where it makes sense. I understand the 2nd point I made might require a ton more work so I'm also available to help out if necessary.

@tale commented on GitHub (Sep 10, 2025): I'd be fine with this change assuming it will be in 0.27 or a new major release. Since this will create breaking changes for the API I would also like to see 2 different changes that should hopefully become easier with the switch to connectRPC. - The OpenAPI document should be full spec, including the version and all, the missing metadata that is currently not there. - API routes need to align with these error codes: https://connectrpc.com/docs/protocol/#error-codes. I've had too many scenarios where the REST API will return a `5xx` status code and then have a JSON body with an error that *isn't* a server error. Otherwise, I fully support this change and would like the opportunity to test it early and utilize the breaking change to try and refine the API design where it makes sense. I understand the 2nd point I made might require a ton more work so I'm also available to help out if necessary.
Author
Owner

@ich777 commented on GitHub (Sep 10, 2025):

Yeah I‘m also fine with that change, I think @tale said everything.

@ich777 commented on GitHub (Sep 10, 2025): Yeah I‘m also fine with that change, I think @tale said everything.
Author
Owner

@kradalby commented on GitHub (Sep 10, 2025):

We are more likely going to switch to implement Tailscale's API instead of using connectrpc.

@kradalby commented on GitHub (Sep 10, 2025): We are more likely going to switch to implement Tailscale's API instead of using connectrpc.
Author
Owner

@majst01 commented on GitHub (Sep 11, 2025):

Bonus would be to be able to use the tailscale operator with headscale as well !

@majst01 commented on GitHub (Sep 11, 2025): Bonus would be to be able to use the tailscale operator with headscale as well !
Author
Owner

@kradalby commented on GitHub (Sep 11, 2025):

Bonus would be to be able to use the tailscale operator with headscale as well !

I would say might, we still are not going to implement oauth. If it can run with our wide open keys then maybe.

@kradalby commented on GitHub (Sep 11, 2025): > Bonus would be to be able to use the tailscale operator with headscale as well ! I would say might, we still are not going to implement oauth. If it can run with our wide open keys then maybe.
Author
Owner

@ArcticLampyrid commented on GitHub (Dec 3, 2025):

Another contender to using connect and grpc would be to leverage the now stable tailscale v2 api client, and use all the types in it: 9ce246ebbf/devices.go (L70)

I understand that, for you, the main concern may be the hassle that comes with manually managing type drift. However, I believe adopting these types is a much worse choice than manually managing drift—at least for request parameters.

  • If you manage drift manually, you will correctly fail when you encounter unknown fields.
  • But if you use a “correct” type (one that may have had new fields added without your knowledge), those unknown fields will be silently ignored by the API handler, which is unacceptable.
    

When managing drift manually, it actually makes the types better reflect how well we keep up with the API.

@ArcticLampyrid commented on GitHub (Dec 3, 2025): > Another contender to using connect and grpc would be to leverage the now stable tailscale v2 api client, and use all the types in it: https://github.com/tailscale/tailscale-client-go-v2/blob/9ce246ebbf4e72f25327e932a4caf066cc63bb12/devices.go#L70 I understand that, for you, the main concern may be the hassle that comes with manually managing type drift. However, I believe adopting these types is a much worse choice than manually managing drift—at least for request parameters. - If you manage drift manually, you will correctly fail when you encounter unknown fields. - But if you use a “correct” type (one that may have had new fields added without your knowledge), those unknown fields will be silently ignored by the API handler, which is unacceptable.  When managing drift manually, it actually makes the types better reflect how well we keep up with the API.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/headscale#886