Documentation ¶
Overview ¶
Package negotiator is a content negotiation library aimed to support strong content typing for RESTful HTTP services. This library implements both Accept and Content-Type header parsers and struct variants that are fully compliant with both RFC-6839 and RFC-7231.
Index ¶
Examples ¶
Constants ¶
const ( // AcceptParamsQuality is the default quality of a media range with specified // accept-params. (e.g text/html;level=1) AcceptParamsQuality float64 = 1.0 // MediaRangeSubTypeQuality is the default quality of a media range with // type and subtype defined. (e.g text/html) MediaRangeSubTypeQuality float64 = 0.9 // MediaRangeWildcardSubtypeQuality is the default weight of a media range // with a wildcarded subtype. (e.g text/*) MediaRangeWildcardSubtypeQuality float64 = 0.8 // MediaRangeWildcardQuality is the default quality for a wildcarded media // range. (e.g */*) MediaRangeWildcardQuality float64 = 0.7 // WildCard is the constant character "*", representing an accept header // wildcard character WildCard string = "*" )
const ContentTypeHeader = "Content-Type"
ContentTypeHeader is the constant value for the key indicating the Content-Type header
Variables ¶
var ( // ErrInvalidMediaRange is the error returned when an invalid accept // media range is parsed ErrInvalidMediaRange = errors.New("Invalid Accept Media Range") // ErrInvalidAcceptParam is the error returned when an invalid accept // parameter is parsed ErrInvalidAcceptParam = errors.New("Invalid Accept Parameter") )
var ( // ErrNoContentType is the error returned if an accept header cannot be matched // in the current registry ErrNoContentType = errors.New("No Acceptable Content Type") )
Functions ¶
func MarshalMedia ¶
func MarshalMedia(w io.Writer, cn ContentNegotiator, acpt *Accept) error
MarshalMedia marshals the ContentNegotiator to the provided io.Writer, based on an Accept. An error is returned if the ContentNegotiator's MarshalMedia call fails, or if the data can't be written to the io.Writer
func UnmarshalMedia ¶
func UnmarshalMedia(req *http.Request, cn ContentNegotiator) error
UnmarshalMedia handles unmarshalling an http.Request body, using a ContentNegotiator instance. An error is returned if no Content-Type header was provided, if the provided Content-Type header was poorly formatted, or if the body of the http.Request could not be read.
Types ¶
type Accept ¶
type Accept struct { MediaRange mediaRange AcceptParams mediaParams Quality float64 AcceptExt acceptExt }
Accept is the struct representation of a single accept header value
func ParseAccept ¶
ParseAccept parses the provided accept header and returns a newly created Accept struct, and a conditional error
type AcceptHeader ¶
type AcceptHeader []*Accept
AcceptHeader is a slice of individual Accept instances representing an entire accept header
func ParseHeader ¶
func ParseHeader(header string) (AcceptHeader, error)
ParseHeader parses an entire Accept header into an AcceptHeader instance and sorts it according to the relative quality of the accept headers provided
type ContentNegotiator ¶
type ContentNegotiator interface { // ContentType accepts the provided Accept header struct and returns the // matched content type, or an error ContentType(*Accept) (string, error) // MarshalMedia returns a raw byte slice containing an appropriately rendered // representation of the provided resource, or an error. MarshalMedia(*Accept) ([]byte, error) // UnmarshalMedia accepts the content type and content type parameters // provided in a request, as well as the raw request body, and unmarshals it // into the ContentNegotiator implementation struct UnmarshalMedia(string, ContentTypeParams, []byte) error }
The ContentNegotiator interface defines the mechanism through which arbitrary interfaces can be provided information about the provided Accept and Content-Type headers, to control marshalling and unmarshalling request/response data as correctly as possible. Optionally, requests may be rejected if provided arguments are invalid, unacceptable, or otherwise erronenous for a given resource.
type ContentTypeParams ¶
ContentTypeParams is a type alias for a map of string to strings, representing any parameters passed to the Content-Type header
type Registry ¶
type Registry map[string]interface{}
Registry is a content type registry used for managing a mapping of media ranges to the interfaces that represent those resources
Example ¶
package main import ( "bytes" "encoding/json" "fmt" "github.com/moogar0880/negotiator" ) func main() { type Message struct { Name string Greeting string } type greeting struct { Phrase string Language string } type MessageV2 struct { Name string Greeting greeting } // define a registry that can handle the media types for our message structs registry := negotiator.NewRegistry() registry.Register("application/vnd.message.v1+json", Message{}) registry.Register("application/vnd.message.v2+json", MessageV2{}) // negotiate a predefined accept header, erroring if we don't support any of // the provided media types. Spoiler Alert - We do. acptHeader := "application/json, application/vnd.message.v1+json" model, accept, err := registry.Negotiate(acptHeader) if err != nil { fmt.Printf("Invalid Accept Header: %s", accept.MediaRange) return } // Dump our response (json encoded) into a buffer and print the result w := bytes.NewBuffer([]byte{}) switch model.(type) { default: msg := MessageV2{Name: "John Doe", Greeting: greeting{ Phrase: "Hello", Language: "English"}, } json.NewEncoder(w).Encode(&msg) case Message: msg := Message{Name: "John Doe", Greeting: "Hello"} json.NewEncoder(w).Encode(&msg) } fmt.Println(w.String()) }
Output: {"Name":"John Doe","Greeting":"Hello"}
func (Registry) ContentType ¶
func (r Registry) ContentType(header string) (interface{}, ContentTypeParams, error)
ContentType parses the provided Content-Type header and attempts to find an interface which implements the specified content type