Skip to content

Commit

Permalink
Add headers for requesting and receiving the server version and other…
Browse files Browse the repository at this point in the history
… debug information
  • Loading branch information
josephschorr committed Apr 27, 2022
1 parent 0bc3020 commit 278411a
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 5 deletions.
44 changes: 44 additions & 0 deletions pkg/requestmeta/requestmeta.go
@@ -0,0 +1,44 @@
package requestmeta

import (
"context"

"google.golang.org/grpc/metadata"
)

// RequestMetadataHeaderKey defines a key in the request metadata header.
type RequestMetadataHeaderKey string

// BoolRequestMetadataHeaderKey defines a key for a boolean vlaue in the request metadata header.
type BoolRequestMetadataHeaderKey RequestMetadataHeaderKey

const (
// RequestServerVersion, if specified in a request header, asks SpiceDB to return its
// server version in the response header (if supported).
// Value: `1`
RequestServerVersion BoolRequestMetadataHeaderKey = "io.spicedb.requestversion"

// RequestDebugInformation, if specified in a request header, asks SpiceDB to return fully debug
// information.
// Value: `1`
RequestDebugInformation BoolRequestMetadataHeaderKey = "io.spicedb.requestdebuginfo"
)

// AddRequestHeaders returns a new context with the given values as request headers.
func AddRequestHeaders(ctx context.Context, keys ...BoolRequestMetadataHeaderKey) context.Context {
values := make(map[RequestMetadataHeaderKey]string, len(keys))
for _, key := range keys {
values[RequestMetadataHeaderKey(key)] = "1"
}
return SetRequestHeaders(ctx, values)
}

// SetRequestHeaders returns a new context with the given values as request headers.
func SetRequestHeaders(ctx context.Context, values map[RequestMetadataHeaderKey]string) context.Context {
pairs := make([]string, 0, len(values)*2)
for key, value := range values {
pairs = append(pairs, string(key))
pairs = append(pairs, value)
}
return metadata.NewOutgoingContext(ctx, metadata.Pairs(pairs...))
}
46 changes: 41 additions & 5 deletions pkg/responsemeta/responsemeta.go
Expand Up @@ -15,6 +15,19 @@ type ResponseMetadataHeaderKey string
const (
// RequestID is the key in the response header metadata for the request's tracking ID, if any.
RequestID ResponseMetadataHeaderKey = "io.spicedb.respmeta.requestid"

// ServerVersion is the key in the response header metadata holding the version of the server
// handling the API request, if requested via a request header.
ServerVersion ResponseMetadataHeaderKey = "io.spicedb.debug.version"

// DatastoreType is the key in the response header metadata holding the type of datastore for
// the server, if requested via a request header.
DatastoreType ResponseMetadataHeaderKey = "io.spicedb.debug.datastore"

// Configuration is the key in the response header metadata holding the configuration (arguments
// and environment variables) for the server, if requested via a request header. It will be repeated
// for each value.
Configuration ResponseMetadataHeaderKey = "io.spicedb.debug.configuration"
)

// ResponseMetadataTrailerKey defines a key in the response metadata trailer.
Expand Down Expand Up @@ -52,16 +65,39 @@ func SetResponseTrailerMetadata(ctx context.Context, values map[ResponseMetadata
return grpc.SetTrailer(ctx, metadata.Pairs(pairs...))
}

// GetIntResponseTrailerMetadata retrieves an integer value for the given key in the trailer
// ListResponseTrailerMetadata retrieves the string value(s) for the given key in the trailer
// metadata of a SpiceDB API response.
func GetIntResponseTrailerMetadata(trailer metadata.MD, key ResponseMetadataTrailerKey) (int, error) {
func ListResponseTrailerMetadata(trailer metadata.MD, key ResponseMetadataTrailerKey) ([]string, error) {
values := trailer.Get(string(key))
if len(values) == 0 {
return 0, fmt.Errorf("key `%s` not found in trailer", key)
return []string{}, fmt.Errorf("key `%s` not found in trailer", key)
}

return values, nil
}

// GetResponseTrailerMetadata retrieves a string value for the given key in the trailer
// metadata of a SpiceDB API response.
func GetResponseTrailerMetadata(trailer metadata.MD, key ResponseMetadataTrailerKey) (string, error) {
values, err := ListResponseTrailerMetadata(trailer, key)
if err != nil {
return "", err
}

if len(values) != 1 {
return 0, fmt.Errorf("key `%s` found multiple times in trailer", key)
return "", fmt.Errorf("key `%s` found multiple times in trailer", key)
}

return values[0], nil
}

// GetIntResponseTrailerMetadata retrieves an integer value for the given key in the trailer
// metadata of a SpiceDB API response.
func GetIntResponseTrailerMetadata(trailer metadata.MD, key ResponseMetadataTrailerKey) (int, error) {
found, err := GetResponseTrailerMetadata(trailer, key)
if err != nil {
return 0, err
}

return strconv.Atoi(values[0])
return strconv.Atoi(found)
}

0 comments on commit 278411a

Please sign in to comment.