Skip to content

Allow custom headers and extensions for twirp clients and servers; unify traits; unify error type #212

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: main
Choose a base branch
from

Conversation

tclem
Copy link
Member

@tclem tclem commented Jul 11, 2025

This is an alternative to #201 with an expanded scope of capabilities. This is very much a breaking change so we should discuss if that's worth it.

Here are the highlights:

  1. No more Context. The same capabilities now exist via http request and response Extensions and Headers.
  2. Clients and servers now share a single trait (the rpc interface).
  3. It is possible to set custom headers on requests (client side) and it's possible for server handlers to read request headers and set custom response headers.
  4. The same ☝🏻 is true for extensions to allow interactivity with middleware.
  5. All the above is accomplished by using http::request::Request<In> and http::response::Response<Out> where In and Out are the individual rpc message types.

The trait interfaces do get slightly more complicated, but we get to drop context (was only implemented on the server trait). You can see in the examples how this works — I don't think it's too bad, but curious to hear feedback here.

EDIT:

One additional change is unifying and simplifying the error types. There is now just TwirpErrorResponse, which isn't a true Rust error - it just models the twirp error response spec. This change dramatically simplified a bunch of code in our project. This error is really only to be used at the boundaries: it's one step away from an axum Response.

@Copilot Copilot AI review requested due to automatic review settings July 11, 2025 20:40
@tclem tclem requested a review from a team as a code owner July 11, 2025 20:40
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a significant breaking change to the twirp-rs library by removing the Context abstraction and unifying client and server traits to use HTTP Request and Response types directly. The changes enable custom headers and extensions support while simplifying the API surface.

Key changes:

  • Replaces Context with direct HTTP request/response handling using extensions and headers
  • Unifies client and server traits to share the same interface
  • Updates method signatures to use http::Request<T> input and http::Response<T> output types

Reviewed Changes

Copilot reviewed 7 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
crates/twirp/src/context.rs Removes the entire Context implementation
crates/twirp/src/lib.rs Updates exports to remove Context and add Request/Response
crates/twirp/src/server.rs Refactors request handling to work with HTTP types directly
crates/twirp/src/client.rs Updates client to handle HTTP Request/Response with headers and extensions
crates/twirp/src/details.rs Updates router builder to use new function signatures
crates/twirp/src/test.rs Updates test implementations to use new HTTP-based API
crates/twirp-build/src/lib.rs Updates code generation to produce unified traits
Comments suppressed due to low confidence (1)

Copy link
Contributor

@CleanCut CleanCut left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really nice! 😄

Copy link
Contributor

@aneubeck aneubeck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this more.

I also think that we should implement test-support directly into the twirp::Client, i.e. that one can register in-process backends which bypass all the http stack.
I guess this should be pretty straight-forward as well and essentially allow us to remove all the ugly wrapper code we currently have.

@tclem tclem marked this pull request as draft July 15, 2025 21:16
@tclem tclem changed the title WIP: Allow custom headers and extensions for twirp clients and servers; unify traits Allow custom headers and extensions for twirp clients and servers; unify traits; unify error type Jul 17, 2025
@tclem tclem marked this pull request as ready for review July 17, 2025 22:24
@@ -231,6 +231,12 @@ impl TwirpErrorResponse {
d
}
});
if let Some(ref retry_after) = self.retry_after {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since you insert the retry_after information into the map anyways, you could also read it from the map instead of having a separate field which you try to keep in sync?

.header(header::CONTENT_TYPE, "application/json");

if let Some(duration) = self.retry_after {
resp = resp.header(header::RETRY_AFTER, duration.as_secs().to_string());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the retry_after information added twice now, once to the header and once in the metadata body?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up removing this entire and implementing manually in blackbird. I might revisit in a follow up.

Copy link
Contributor

@aneubeck aneubeck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm... I read through some parts of the corresponding blackbird change and everything there looks reasonable to me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants