Skip to content

Triple header/trailer usage pattern proposal #2422

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
DMwangnima opened this issue Sep 11, 2023 · 3 comments
Open

Triple header/trailer usage pattern proposal #2422

DMwangnima opened this issue Sep 11, 2023 · 3 comments

Comments

@DMwangnima
Copy link
Contributor

New Triple is based on connect-go (https://github.com/connectrpc/connect-go) which makes use of Golang generic feature. For instance, client and server side code of unary invocation would be like this:

// client side
Ping(context.Context, *connect_go.Request[v1.PingRequest]) (*connect_go.Response[v1.PingResponse], error)

// server side
Ping(context.Context, *connect_go.Request[v1.PingRequest]) (*connect_go.Response[v1.PingResponse], error)

// uniform Request
type Request[T any] struct {
	Msg *T

	spec   Spec
	peer   Peer
	header http.Header
}

// uniform Response
type Response[T any] struct {
	Msg *T

	header  http.Header
	trailer http.Header
}

Users could inject or receive headers and trailers directly from Request and Response just like this:

// client side
req := connect.NewRequest(&pingv1.PingRequest{})
req.Header().Set("hello", "wourld")
resp, err := Ping(context.Background(), req)
headers := resp.Header().Values("hello")
trailers := resp.Trailer().Values()
// do something with headers and trailers
// server side
func (p *pingServer) Ping(ctx context.Context, req *connect.Request[pingv1.PingRequest]) (*connect.Response[pingv1.PingResponse], error) {
	headers := req.Headers().Values("hello")
        // do something with headers

	response := connect.NewResponse(
		&pingv1.PingResponse{},
	)
        // return headers and trailers
	response.Header().Set(handlerHeader, headerValue)
	response.Trailer().Set(handlerTrailer, trailerValue)
	return response, nil
}

This pattern is very uniform and easy to understand. But since we decided not to use generics API for compatibility, new Triple has to make use of some grpc-like pattern to send and receive headers and trailers.

@DMwangnima
Copy link
Contributor Author

client-side sending headers

ctx := triple.NewOutgoingContext(context.Background(), http.Header{"hello", "triple"})
resp, err := cli.Greet(ctx, &v1.GreetRequest{})
// or
ctx := triple.NewOutgoingContext(context.Background(), http.Header{"hello", "triple"})
ctx = triple.AppendToOutgoingContext(ctx, "hello", "dubbo", "hey", "hessian")
resp, err := cli.Greet(ctx, &v1.GreetRequest{})
// headers would be hello: triple, dubbo; hey: hessian.

client-side receiving headers and trailers

WIP

server-side receiving headers

func (srv *Server) Greet(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) {
	headers, ok := triple.FromIncomingContext(ctx)
	// do something with headers and ok flag
}

server-side sending headers and trailers

func (srv *Server) Greet(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) {
	triple.SetHeader(ctx, http.Header{"hi", "triple"})
        triple.SetTrailer(ctx, http.Header("end", "end"))
}
func (srv *Server) GreetStream(ctx context.Context, stream greet.GreetService_GreetStreamServer) error {
      // stream could also make use of triple.SetHeader and triple.SetTrailer
      // headers would be sent in the first call of stream.Send
      // in some scenarios, users would hope to send headers directly
      triple.Send(ctx, http.Header{"hi", "triple"})
}

@DMwangnima
Copy link
Contributor Author

@marsevilspirit
Copy link
Contributor

done

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

No branches or pull requests

2 participants