ETags and 304 Not Modified response in grpc REST gateway

Viewed 1573

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?

1 Answers

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.

Related