I am auto-generating a REST API from a gRPC spec using the grpc-gateway project from Github. In this REST API, I'd like to support ETag
headers and 304 Not Modified responses.
As far as I understand, normally you would create a response in the gRPC server with a specific status code, and that status code will then get translated into an HTTP status code by the grpc-gateway. However, since standard gRPC doesn't really support caching concepts, there is no gRPC status code that maps to the HTTP 304 status code.
Using grpc-gateway, it seems to be possible to customise HTTP status codes whenever the gRPC status code is en error code (overwriting the runtime.HTTPError function). However, I haven't found any way to customise the HTTP response code when the gRPC repsonse code is OK.
So, are there any recommended ways of achieving this?
Here's an example to implement basic etag and 304 responses using a custom forwarder.
You can refer to these directions to get setup, then implement the method along the lines of:
func forwardGetPost(ctx context.Context, mux *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, req *http.Request, resp proto.Message, opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
// add cache-control rules for this proxy endpoint
w.Header().Add("Cache-Control", "max-age=60")
// create an etag
// (when the response represents some entity from the db it may have a last edited timestamp)
p := resp.(*Post)
etag := fmt.Sprintf("W/%q", p.GetLastEdited())
w.Header().Add("ETag", etag)
// check whether the request provides an etag
inm := req.Header.Get("If-None-Match")
if inm != "" {
if inm == etag {
w.WriteHeader(http.StatusNotModified)
}
}
runtime.ForwardResponseMessage(ctx, mux, marshaler, w, req, resp, opts...)
}
This does not prevent the proxy from making a request to the grpc server, but it will prevent sending those bytes back to the client when etags match.