Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add responsemeta package that defines metadata on SpiceDB API responses #40

Merged
merged 1 commit into from Nov 30, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
67 changes: 67 additions & 0 deletions pkg/responsemeta/responsemeta.go
@@ -0,0 +1,67 @@
package responsemeta

import (
"context"
"fmt"
"strconv"

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

// ResponseMetadataHeaderKey defines a key in the response metadata header.
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"
)

// ResponseMetadataTrailerKey defines a key in the response metadata trailer.
type ResponseMetadataTrailerKey string

const (
// DispatchedOperationsCount is the key in the response trailer metadata for
// the number of dispatched operations that were needed to perform the overall
// API call.
DispatchedOperationsCount ResponseMetadataTrailerKey = "io.spicedb.respmeta.dispatchedoperationscount"

// CachedOperationsCount is the key in the response trailer metadata for
// the number of *cached* operations that would have been otherwise dispatched
// to perform the overall API call.
CachedOperationsCount ResponseMetadataTrailerKey = "io.spicedb.respmeta.cachedoperationscount"
)

// SetResponseHeaderMetadata sets the external response metadata header on the given context.
func SetResponseHeaderMetadata(ctx context.Context, values map[ResponseMetadataHeaderKey]string) error {
pairs := make([]string, 0, len(values)*2)
for key, value := range values {
pairs = append(pairs, string(key))
pairs = append(pairs, value)
}
return grpc.SetHeader(ctx, metadata.Pairs(pairs...))
}

// SetResponseTrailerMetadata sets the external response metadata trailer on the given context.
func SetResponseTrailerMetadata(ctx context.Context, values map[ResponseMetadataTrailerKey]string) error {
pairs := make([]string, 0, len(values)*2)
for key, value := range values {
pairs = append(pairs, string(key))
pairs = append(pairs, value)
}
return grpc.SetTrailer(ctx, metadata.Pairs(pairs...))
}

// 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) {
values := trailer.Get(string(key))
if len(values) == 0 {
return -1, fmt.Errorf("key `%s` not found in trailer", key)
}
if len(values) != 1 {
return -1, fmt.Errorf("key `%s` found multiple times in trailer", key)
}

return strconv.Atoi(values[0])
}