ctxmeta

package
v0.9.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2021 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package ctxmeta provides a helper type for request-scoped metadata. This package is inspired by https://github.com/peterbourgon/ctxdata. (License: https://github.com/peterbourgon/ctxdata/blob/master/LICENSE) The original package doesn't support collecting different groups of contextual data. This forked version allows it.

Example (Middleware)
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/DoNewsCode/core/ctxmeta"
)

type Server struct{}

func NewServer() *Server {
	return &Server{}
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	bag := ctxmeta.GetBaggage(r.Context())
	bag.Set("method", r.Method)
	bag.Set("path", r.URL.Path)
	bag.Set("content_length", r.ContentLength)
	fmt.Fprintln(w, "OK")
}

type Middleware struct {
	next http.Handler
}

func NewMiddleware(next http.Handler) *Middleware {
	return &Middleware{next: next}
}

func (mw *Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	bag, ctx := ctxmeta.Inject(r.Context())

	defer func() {
		for _, kv := range bag.Slice() {
			fmt.Printf("%s: %v\n", kv.Key, kv.Val)
		}
	}()

	mw.next.ServeHTTP(w, r.WithContext(ctx))
}

func main() {
	server := NewServer()
	middleware := NewMiddleware(server)
	testserver := httptest.NewServer(middleware)
	defer testserver.Close()
	http.Post(testserver.URL+"/path", "text/plain; charset=utf-8", strings.NewReader("hello world"))

}
Output:

method: POST
path: /path
content_length: 11

Index

Examples

Constants

This section is empty.

Variables

View Source
var DefaultMetadata = MetadataSet{/* contains filtered or unexported fields */}

DefaultMetadata contains the default key for Baggage in the context. Use this if there is no need to categorize metadata, ie. put all data in one baggage.

View Source
var ErrIncompatibleType = errors.New("incompatible type")

ErrIncompatibleType is returned by Unmarshal if the value associated with a key isn't assignable to the provided target.

View Source
var ErrNoBaggage = errors.New("no baggage in context")

ErrNoBaggage is returned by accessor methods when they're called on a nil pointer receiver. This typically means From was called on a context that didn't have Baggage injected into it previously via Inject.

View Source
var ErrNotFound = errors.New("key not found")

ErrNotFound is returned by Get or other accessors when the key isn't present.

Functions

This section is empty.

Types

type Baggage

type Baggage struct {
	// contains filtered or unexported fields
}

Baggage is an opaque type that can be injected into a context at e.g. the start of a request, updated with metadata over the course of the request, and then queried at the end of the request.

When a new request arrives in your program, HTTP server, etc., use the New constructor with the incoming request's context to construct a new, empty Baggage. Use the returned context for all further operations on that request. Use the From helper function to retrieve a previously-injected Baggage from a context, and set or get metadata. At the end of the request, all metadata collected will be available from any point in the callstack.

func GetBaggage

func GetBaggage(ctx context.Context) *Baggage

GetBaggage returns the default Baggage stored in the context.

func Inject

func Inject(ctx context.Context) (*Baggage, context.Context)

Inject constructs a Baggage object and injects it into the provided context under the default context key. Use the returned context for all further operations. The returned Data can be queried at any point for metadata collected over the life of the context.

func (*Baggage) Delete

func (b *Baggage) Delete(key interface{}) (err error)

Delete key from baggage. If key doesn't exist, it returns ErrNotFound. If the MetadataSet is not associated with an initialized baggage, it returns ErrNoBaggage.

func (*Baggage) Get

func (b *Baggage) Get(key string) (value interface{}, err error)

Get the value associated with key, or return ErrNotFound. If this method is called on a nil Baggage pointer, it returns ErrNoBaggage.

func (*Baggage) Map

func (b *Baggage) Map() map[string]interface{}

Map returns a map of key to value.

func (*Baggage) Set

func (b *Baggage) Set(key string, value interface{}) (err error)

Set key to value. If key already exists, it will be overwritten. If this method is called on a nil Baggage pointer, it returns ErrNoBaggage.

func (*Baggage) Slice

func (b *Baggage) Slice() []KeyVal

Slice returns a slice of key/value pairs in the order in which they were set.

func (*Baggage) Unmarshal

func (b *Baggage) Unmarshal(path string, target interface{}) error

Unmarshal get the value at given path, and store it into the target variable. Target must be a pointer to an assignable type. Unmarshal will return ErrNotFound if the key is not found, and ErrIncompatibleType if the found value is not assignable to target. Unmarshal also implements contract.ConfigUnmarshaler.

Example

This example demonstrates how to use Unmarshal to retrieve metadata into an arbitrary type.

package main

import (
	"context"
	"fmt"
	"net/http"

	"github.com/DoNewsCode/core/ctxmeta"
)

func main() {
	type DomainError struct {
		Code   int
		Reason string
	}

	bag, _ := ctxmeta.Inject(context.Background())
	derr := DomainError{Code: http.StatusTeapot, Reason: "Earl Gray exception"}
	bag.Set("err", derr)

	if target := (DomainError{}); bag.Unmarshal("err", &target) == nil {
		fmt.Printf("DomainError Code=%d Reason=%q\n", target.Code, target.Reason)
	}

}
Output:

DomainError Code=418 Reason="Earl Gray exception"

func (*Baggage) Update

func (b *Baggage) Update(key string, callback func(value interface{}) interface{}) (err error)

Update key to the value returned from the callback. If key doesn't exist, it returns ErrNotFound. If this method is called on a nil Baggage pointer, it returns ErrNoBaggage.

type KeyVal

type KeyVal struct {
	Key string
	Val interface{}
}

KeyVal combines a string key with its abstract value into a single tuple. It's used internally, and as a return type for Slice.

type MetadataSet

type MetadataSet struct {
	// contains filtered or unexported fields
}

MetadataSet is a group key to the contextual data stored the context. The data stored with different MetadataSet instances are not shared.

func New

func New() *MetadataSet

New constructs a new set of metadata. This metadata can be used to retrieve a group of contextual data. The data stored with different MetadataSet instances are not shared.

func (*MetadataSet) GetBaggage

func (m *MetadataSet) GetBaggage(ctx context.Context) *Baggage

GetBaggage returns the Baggage stored in the context.

func (*MetadataSet) Inject

func (m *MetadataSet) Inject(ctx context.Context) (*Baggage, context.Context)

Inject constructs a Baggage object and injects it into the provided context under the context key determined the metadata instance. Use the returned context for all further operations. The returned Baggage can be queried at any point for metadata collected over the life of the context.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL