MCPcopy
hub / github.com/connectrpc/connect-go / NewUnaryHandler

Function NewUnaryHandler

handler.go:37–112  ·  view source on GitHub ↗

NewUnaryHandler constructs a [Handler] for a request-response procedure.

(
	procedure string,
	unary func(context.Context, *Request[Req]) (*Response[Res], error),
	options ...HandlerOption,
)

Source from the content-addressed store, hash-verified

35
36// NewUnaryHandler constructs a [Handler] for a request-response procedure.
37func NewUnaryHandler[Req, Res any](
38 procedure string,
39 unary func(context.Context, *Request[Req]) (*Response[Res], error),
40 options ...HandlerOption,
41) *Handler {
42 // Wrap the strongly-typed implementation so we can apply interceptors.
43 untyped := UnaryFunc(func(ctx context.Context, request AnyRequest) (AnyResponse, error) {
44 if err := ctx.Err(); err != nil {
45 return nil, err
46 }
47 typed, ok := request.(*Request[Req])
48 if !ok {
49 return nil, errorf(CodeInternal, "unexpected handler request type %T", request)
50 }
51 res, err := unary(ctx, typed)
52 if res == nil && err == nil {
53 // This is going to panic during serialization. Debugging is much easier
54 // if we panic here instead, so we can include the procedure name.
55 panic(procedure + " returned nil *connect.Response and nil error") //nolint: forbidigo
56 }
57 if res == nil {
58 // Avoid returning a typed nil (*Response[Res]) as an AnyResponse interface value.
59 return nil, err
60 }
61 return res, err
62 })
63 config := newHandlerConfig(procedure, StreamTypeUnary, options)
64 if interceptor := config.Interceptor; interceptor != nil {
65 untyped = interceptor.WrapUnary(untyped)
66 }
67 // Given a stream, how should we call the unary function?
68 implementation := func(ctx context.Context, conn StreamingHandlerConn) error {
69 request, err := receiveUnaryRequest[Req](conn, config.Initializer)
70 if err != nil {
71 return err
72 }
73 // Add the request header to the context, and store the response header
74 // and trailer to propagate back to the caller.
75 info := &handlerCallInfo{
76 peer: request.Peer(),
77 spec: request.Spec(),
78 method: request.HTTPMethod(),
79 requestHeader: request.Header(),
80 }
81 ctx = newHandlerContext(ctx, info)
82 response, err := untyped(ctx, request)
83 // Add response headers/trailers from the context callinfo into the conn if they exist
84 if info.responseHeader != nil {
85 mergeNonProtocolHeaders(conn.ResponseHeader(), info.responseHeader)
86 }
87 if info.responseTrailer != nil {
88 mergeNonProtocolHeaders(conn.ResponseTrailer(), info.responseTrailer)
89 }
90 if err != nil {
91 return err
92 }
93
94 // Add response headers/trailers from the response into the conn if they exist

Callers 9

TestDynamicHandlerFunction · 0.92
NewCollideServiceHandlerFunction · 0.92
NewPingServiceHandlerFunction · 0.92
NewTestServiceHandlerFunction · 0.92
NewTestServiceHandlerFunction · 0.92
NewTestServiceHandlerFunction · 0.92
NewExampleV1BetaHandlerFunction · 0.92
NewUnaryHandlerSimpleFunction · 0.85

Calls 15

UnaryFuncFuncType · 0.85
errorfFunction · 0.85
newHandlerConfigFunction · 0.85
newHandlerContextFunction · 0.85
mergeNonProtocolHeadersFunction · 0.85
mappedMethodHandlersFunction · 0.85
sortedAllowMethodValueFunction · 0.85
sortedAcceptPostValueFunction · 0.85
newProtocolHandlersMethod · 0.80
WrapUnaryMethod · 0.65
PeerMethod · 0.65
SpecMethod · 0.65

Tested by 2

TestDynamicHandlerFunction · 0.74