negotiator

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Apr 25, 2020 License: Apache-2.0 Imports: 2 Imported by: 0

README

negotiator

A compact library for handling HTTP content negotiation for RESTful APIs.

GoDoc Build Status Coverage Status Release License

What is it?

negotiator enhances the interoperability of your HTTP API by equipping it with capabilities to facilitate proactive, reactive, and transparent content negotiation. This is accomplished by providing customizable and extendable functionality that adheres to RFC specifications, as well as industry adopted algorithms. With negotiator, your API no longer needs to take on the burden of implementing content negotiation, allowing you to focus on simply defining your representations and letting us do the rest.

Why use it?

There are many reasons why you should leave your HTTP content negotiation to us:

  • content negotiation algorithms are not trivial, with some algorithms detailed in lengthy RFC documentation while others lacking any standardization at all.
  • allows you to focus purely on defining your representations.
  • maximizes your APIs interoperability, lowering friction for client adoption.
  • unlocks all forms of content negotiation, allowing your API leverage different kinds of negotiation algorithms to support all of your flows.
  • customization allowing you to disable or enable particular features.
  • extensibility allowing you to define your own algorithms.

How to use it?

Quickstart
http.HandleFunc("/foo", func(rw http.ResponseWriter, r *http.Request) {

	// gather representations.
	representations := []representation.Representation { Foo { ID: 1 } }

	// choose a negotiator.
	p := proactive.Default

	// negotiate.
	ctx := negotiator.NegotiationContext { Request: r, ResponseWriter: rw }
	if err := p.Negotiate(ctx, representations...); err != nil {
		http.Error(rw, "oops!", 500)
	}
})
Examples

If you are looking for hands-on examples, we've created a sample RESTful API, called tutor, that leverages this library.

Proactive
Construction

For out of the box proactive negotiation support, use proactive.Default, which is the default proactive negotiator.

// retrieves the default proactive negotiator.
p := proactive.Default

In situations where more customization is required, use the proactive.New constructor function and specify options as arguments.

// constructs a proactive negotiator with the provided options.
p := proactive.New(
	proactive.DisableStrictMode(),
	proactive.DisableNotAcceptableRepresentation(),
)
Strict Mode

According to RFC7231, when none of the representations match the values provided for a particular proactive content negotiation header, the origin server can honor that header and return 406 Not Acceptable, or disregard the header field by treating the resource as if it is not subject to content negotiation.

The behavior of honoring the header in these scenarios is what we refer to as strict mode. It is possible to configure strict mode for each individual proactive negotiation header, or disable strict mode for all. Strict mode is enabled for all headers by default.

Reactive
Construction

For out of the box reactive negotiation support, use reactive.Default, which is the default reactive negotiator.

// retrieves the default reactive negotiator.
p := reactive.Default

In situations where more customization is required, use the reactive.New constructor function and specify options as arguments.

// constructs a reactive negotiator with the provided options.
p := reactive.New(
	reactive.Logger(l),
)
Transparent
Construction

For out of the box transparent negotiation support, use transparent.Default, which is the default transparent negotiator.

// retrieves the default transparent negotiator.
p := transparent.Default

In situations where more customization is required, use the transparent.New constructor function and specify options as arguments.

// constructs a transparent negotiator with the provided options.
p := transparent.New(
	transparent.MaximumVariantListSize(5),
)
Logging

We use zap as our logging library of choice. To leverage the logs emitted from the negotiator, utilize the proactive.Logger, reactive.Logger, or transparent.Logger option with a *zap.Logger upon creation.

l, _ := zap.NewDevelopment()

// create a proactive negotiator with logging.
pn := proactive.New(
	proactive.Logger(l),
)

// create a reactive negotiator with logging.
rn := reactive.New(
	reactive.Logger(l),
)

// create a transparent negotiator with logging.
tn := transparent.New(
	transparent.Logger(l),
)
Metrics

For emitting metrics, we use tally. To utilize the metrics emitted from the negotiator, leverage the proactive.Scope, reactive.Scope, or transparent.Scope option with a tally.Scope upon creation.

s := tally.NewTestScope("example", map[string]string{}) 

// create a reactive negotiator with metrics.
rn := reactive.New(
	reactive.Scope(s),
)

// create a proactive negotiator with metrics.
pn := proactive.New(
	proactive.Scope(s),
)

// create a transparent negotiator with metrics.
tn := transparent.New(
	transparent.Scope(s),
)
Emitted Metrics
Name Tag Type Description
[PREFIX.]negotiate negotiator: proactive timer The time spent during proactive negotiation.
[PREFIX.]negotiate negotiator: reactive timer The time spent during reactive negotiation.
[PREFIX.]negotiate negotiator: transparent timer The time spent during transparent negotiation.
[PREFIX.]negotiate.no_content negotiator: proactive counter The count of proactive negotiation resulting in HTTP 204.
[PREFIX.]negotiate.no_content negotiator: reactive counter The count of reactive negotiation resulting in HTTP 204.
[PREFIX.]negotiate.error negotiator: proactive counter The count of proactive negotiation resulting in an error.
[PREFIX.]negotiate.error negotiator: reactive counter The count of reactive negotiation resulting in an error.
[PREFIX.]negotiate.error negotiator: transparent counter The count of transparent negotiation resulting in an error.
[PREFIX.]negotiate.multiple_choices negotiator: reactive counter The count of reactive negotiation resulting in HTTP 302.
[PREFIX.]negotiate.acceptable negotiator: proactive counter The count of reactive negotiation resulting in HTTP 200.
[PREFIX.]negotiate.not_acceptable negotiator: proactive counter The count of reactive negotiation resulting in HTTP 406.

Contribute

Want to lend us a hand? Check out our guidelines for contributing.

License

We are rocking an Apache 2.0 license for this project.

Code of Conduct

Please check out our code of conduct to get up to speed how we do things.

Documentation

Overview

Package negotiator provides implementations utilized by proactive, reactive, and transparent content negotiation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type NegotiationContext

type NegotiationContext struct {
	ResponseWriter http.ResponseWriter
	Request        *http.Request
	IsCreation     bool
}

NegotiationContext represents the context, such as the nature of the request and request itself, in which content negotiation is occuring.

type Negotiator

type Negotiator interface {
	Negotiate(NegotiationContext, ...representation.Representation) error
}

Negotiator represents a content negotiator.

Directories

Path Synopsis
internal
header
Package header provides implementations that define HTTP header behavior necessary to facilitate content negotiation.
Package header provides implementations that define HTTP header behavior necessary to facilitate content negotiation.
representation
Package representation provides internal functionality related to representations.
Package representation provides internal functionality related to representations.
test
Package test provides implementations leveraged within unit tests.
Package test provides implementations leveraged within unit tests.
test/mock
Package mock is a generated GoMock package.
Package mock is a generated GoMock package.
Package proactive implements proactive content negotiation as defined in RFC7231 Section 3.4.1.
Package proactive implements proactive content negotiation as defined in RFC7231 Section 3.4.1.
Package reactive implements reactive content negotiation as defined in RFC7231 Section 3.4.2.
Package reactive implements reactive content negotiation as defined in RFC7231 Section 3.4.2.
Package representation provides implementations that define representations and how to interact with them.
Package representation provides implementations that define representations and how to interact with them.
Package transparent implements transparent content negotiation as defined in RFC2295.
Package transparent implements transparent content negotiation as defined in RFC2295.

Jump to

Keyboard shortcuts

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