You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The WithForwardResponseOption does not allow you to cast to the original response proto when the service has a response_body field set. This makes it very difficult to conditionally attach headers, cookies, or do other conditional logic based off of the response proto.
Register a WithForwardResponseOption function with test:
type fake struct {}
func (f fake) GetObject(ctx context.Context, request *services.GetObjectRequest) (*services.GetObjectResponse, error) {
return &services.GetObjectResponse{Value: "this is the value"}, nil
}
func TestGetValue(t *testing.T) {
type GetValuer interface {
GetValue() string
}
mux := runtime.NewServeMux(runtime.WithForwardResponseOption(func(ctx context.Context, w http.ResponseWriter, m proto.Message) error {
switch m.(type) {
case *services.GetObjectResponse:
t.Logf("Cast to struct ptr")
case GetValuer:
t.Logf("Cast to interface")
default:
t.Errorf("Couldn't cast response to expected format.")
}
return nil
}))
services.RegisterServiceHandlerServer(context.Background(), mux, &fake{})
req := httptest.NewRequest("GET","http://localhost/object", nil)
resp := httptest.NewRecorder()
mux.ServeHTTP(resp, req)
}
Expected behavior
Either "Cast to struct ptr" or "Cast to interface" would get logged and the test would pass.
This behavior would allow headers and cookies to be conditionally attached to the response using the fields that sit alongside the "value" field in the response.
Actual Behavior
The test fails with "Couldn't cast response to expected format."
Your Environment
MacOS 10.15.5
Go 1.13
Potential solutions
The reason this cast doesn't work is because the response proto.Message is embedded in a custom internal struct when response_body is defined. See this example
A few potential solutions in order of preference:
Add a method for this internal struct that returns the embedded proto.Message directly so we can then cast to the interface for the wrapped structure and extract out our response proto. Something like the following (name TBD):
Hi Johanbrandhorst,
It does look like with v2 we can do something like this to get the wrapped proto:
mux := runtime.NewServeMux(runtime.WithForwardResponseOption(func(ctx context.Context, w http.ResponseWriter, m proto.Message) error {
m = m.ProtoReflect().Interface()
switch m := m.(type) {
case *services.GetObjectResponse:
t.Logf("Cast to struct ptr: %q.", m.GetValue())
case GetValuer:
t.Logf("Cast to interface: %q.", m.GetValue())
default:
t.Errorf("Couldn't cast response to expected format.")
}
return nil
}))
Perfect! I think we'll probably leave things as they are then, we do want to encourage people to upgrade to v2. It is basically stable, we're just waiting for a stable protoc-gen-go-grpc release before tagging it.
🐛 Bug Report
The WithForwardResponseOption does not allow you to cast to the original response proto when the service has a
response_body
field set. This makes it very difficult to conditionally attach headers, cookies, or do other conditional logic based off of the response proto.This is a follow up bug report from a chat with @johanbrandhorst in slack.
To Reproduce
response_body
set.Expected behavior
Either "Cast to struct ptr" or "Cast to interface" would get logged and the test would pass.
This behavior would allow headers and cookies to be conditionally attached to the response using the fields that sit alongside the "value" field in the response.
Actual Behavior
The test fails with "Couldn't cast response to expected format."
Your Environment
MacOS 10.15.5
Go 1.13
Potential solutions
The reason this cast doesn't work is because the response proto.Message is embedded in a custom internal struct when response_body is defined. See this example
A few potential solutions in order of preference:
The text was updated successfully, but these errors were encountered: