Skip to content

Commit 65a19df

Browse files
boojackclaude
andcommitted
fix(backend): correct generic type parameter in withHeaderCarrier helper
Problem: The withHeaderCarrier generic function had a type mismatch that caused compilation errors in CI. The function used `T proto.Message` constraint, but Connect's Response type expects the non-pointer message type while protobuf methods return pointers. Error from CI: type T of resp does not match *T (cannot infer T) This occurred because: - Connect methods expect: *connect.Response[v1pb.CreateSessionResponse] - Service methods return: (*v1pb.CreateSessionResponse, error) - Old signature: fn func(context.Context) (T, error) with T proto.Message - This caused T to be inferred as *v1pb.CreateSessionResponse - Leading to return type: *connect.Response[*v1pb.CreateSessionResponse] (wrong!) Solution: Changed generic signature to explicitly handle the pointer/non-pointer distinction: - New signature: fn func(context.Context) (*T, error) with T any - T is now the non-pointer type (e.g., v1pb.CreateSessionResponse) - fn returns *T (e.g., *v1pb.CreateSessionResponse) - Return type is correctly: *connect.Response[T] (e.g., *connect.Response[v1pb.CreateSessionResponse]) Also removed unused "google.golang.org/protobuf/proto" import and improved documentation to clarify the T vs *T distinction. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
1 parent 06a0f8d commit 65a19df

File tree

2 files changed

+11
-9
lines changed

2 files changed

+11
-9
lines changed

server/router/api/v1/connect_services.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,23 @@ func (s *ConnectServiceHandler) UpdateInstanceSetting(ctx context.Context, req *
4242
// AuthService
4343
//
4444
// Auth service methods need special handling for response headers (cookies).
45-
// We use withHeaderCarrier helper to inject a header carrier into the context,
45+
// We use connectWithHeaderCarrier helper to inject a header carrier into the context,
4646
// which allows the service to set headers in a protocol-agnostic way.
4747

4848
func (s *ConnectServiceHandler) GetCurrentSession(ctx context.Context, req *connect.Request[v1pb.GetCurrentSessionRequest]) (*connect.Response[v1pb.GetCurrentSessionResponse], error) {
49-
return withHeaderCarrier(ctx, func(ctx context.Context) (*v1pb.GetCurrentSessionResponse, error) {
49+
return connectWithHeaderCarrier(ctx, func(ctx context.Context) (*v1pb.GetCurrentSessionResponse, error) {
5050
return s.APIV1Service.GetCurrentSession(ctx, req.Msg)
5151
})
5252
}
5353

5454
func (s *ConnectServiceHandler) CreateSession(ctx context.Context, req *connect.Request[v1pb.CreateSessionRequest]) (*connect.Response[v1pb.CreateSessionResponse], error) {
55-
return withHeaderCarrier(ctx, func(ctx context.Context) (*v1pb.CreateSessionResponse, error) {
55+
return connectWithHeaderCarrier(ctx, func(ctx context.Context) (*v1pb.CreateSessionResponse, error) {
5656
return s.APIV1Service.CreateSession(ctx, req.Msg)
5757
})
5858
}
5959

6060
func (s *ConnectServiceHandler) DeleteSession(ctx context.Context, req *connect.Request[v1pb.DeleteSessionRequest]) (*connect.Response[emptypb.Empty], error) {
61-
return withHeaderCarrier(ctx, func(ctx context.Context) (*emptypb.Empty, error) {
61+
return connectWithHeaderCarrier(ctx, func(ctx context.Context) (*emptypb.Empty, error) {
6262
return s.APIV1Service.DeleteSession(ctx, req.Msg)
6363
})
6464
}

server/router/api/v1/header_carrier.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"connectrpc.com/connect"
77
"google.golang.org/grpc"
88
"google.golang.org/grpc/metadata"
9-
"google.golang.org/protobuf/proto"
109
)
1110

1211
// headerCarrierKey is the context key for storing headers to be set in the response.
@@ -86,19 +85,22 @@ func SetResponseHeader(ctx context.Context, key, value string) error {
8685
}))
8786
}
8887

89-
// withHeaderCarrier is a helper for Connect service wrappers that need to set response headers.
88+
// connectWithHeaderCarrier is a helper for Connect service wrappers that need to set response headers.
9089
//
9190
// It injects a HeaderCarrier into the context, calls the service method,
9291
// and applies any headers from the carrier to the Connect response.
9392
//
93+
// The generic parameter T is the non-pointer protobuf message type (e.g., v1pb.CreateSessionResponse),
94+
// while fn returns *T (the pointer type) as is standard for protobuf messages.
95+
//
9496
// Usage in Connect wrappers:
9597
//
96-
// func (s *ConnectServiceHandler) CreateSession(ctx context.Context, req *connect.Request[...]) (*connect.Response[...], error) {
97-
// return withHeaderCarrier(ctx, func(ctx context.Context) (*v1pb.CreateSessionResponse, error) {
98+
// func (s *ConnectServiceHandler) CreateSession(ctx context.Context, req *connect.Request[v1pb.CreateSessionRequest]) (*connect.Response[v1pb.CreateSessionResponse], error) {
99+
// return connectWithHeaderCarrier(ctx, func(ctx context.Context) (*v1pb.CreateSessionResponse, error) {
98100
// return s.APIV1Service.CreateSession(ctx, req.Msg)
99101
// })
100102
// }
101-
func withHeaderCarrier[T proto.Message](ctx context.Context, fn func(context.Context) (T, error)) (*connect.Response[T], error) {
103+
func connectWithHeaderCarrier[T any](ctx context.Context, fn func(context.Context) (*T, error)) (*connect.Response[T], error) {
102104
// Inject header carrier for Connect protocol
103105
ctx = WithHeaderCarrier(ctx)
104106

0 commit comments

Comments
 (0)