web

package
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Jun 2, 2019 License: MIT Imports: 12 Imported by: 1,083

Documentation

Overview

Package web provides a fast and flexible middleware stack and mux.

This package attempts to solve three problems that net/http does not. First, it allows you to specify flexible patterns, including routes with named parameters and regular expressions. Second, it allows you to write reconfigurable middleware stacks. And finally, it allows you to attach additional context to requests, in a manner that can be manipulated by both compliant middleware and handlers.

Example
package main

import (
	"fmt"
	"log"
	"net/http"
	"regexp"

	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
)

func main() {
	m := web.New()

	// Use your favorite HTTP verbs and the interfaces you know and love
	// from net/http:
	m.Get("/hello", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Why hello there!\n")
	})
	m.Post("/login", func(w http.ResponseWriter, r *http.Request) {
		if r.FormValue("password") != "god" {
			http.Error(w, "Hack the planet!", 401)
		}
	})

	// Handlers can optionally take a context parameter, which contains
	// (among other things) a set of bound parameters.
	hello := func(c web.C, w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, %s!\n", c.URLParams["name"])
	}

	// Bind parameters using pattern strings...
	m.Get("/hello/:name", hello)

	// ...or use regular expressions if you need additional power.
	bonjour := regexp.MustCompile(`^/bonjour/(?P<name>[A-Za-z]+)$`)
	m.Get(bonjour, hello)

	// Middleware are a great abstraction for performing logic on every
	// request. Some middleware use the Goji context object to set
	// request-scoped variables.
	logger := func(h http.Handler) http.Handler {
		wrap := func(w http.ResponseWriter, r *http.Request) {
			log.Println("Before request")
			h.ServeHTTP(w, r)
			log.Println("After request")
		}
		return http.HandlerFunc(wrap)
	}
	auth := func(c *web.C, h http.Handler) http.Handler {
		wrap := func(w http.ResponseWriter, r *http.Request) {
			if cookie, err := r.Cookie("user"); err == nil {
				c.Env["user"] = cookie.Value
			}
			h.ServeHTTP(w, r)
		}
		return http.HandlerFunc(wrap)
	}

	// A Middleware stack is a flexible way to assemble the common
	// components of your application, like request loggers and
	// authentication. There is an ecosystem of open-source middleware for
	// Goji, so there's a chance someone has already written the middleware
	// you are looking for!
	m.Use(middleware.EnvInit)
	m.Use(logger)
	m.Use(auth)
}
Output:

Index

Examples

Constants

View Source
const MatchKey = "goji.web.Match"

The key used to store route Matches in the Goji environment. If this key is present in the environment and contains a value of type Match, routing will not be performed, and the Match's Handler will be used instead.

View Source
const ValidMethodsKey = "goji.web.ValidMethods"

The key used to communicate to the NotFound handler what methods would have been allowed if they'd been provided.

Variables

This section is empty.

Functions

This section is empty.

Types

type C

type C struct {
	// URLParams is a map of variables extracted from the URL (typically
	// from the path portion) during routing. See the documentation for the
	// URL Pattern you are using (or the documentation for PatternType for
	// the case of standard pattern types) for more information about how
	// variables are extracted and named.
	URLParams map[string]string
	// Env is a free-form environment for storing request-local data. Keys
	// may be arbitrary types that support equality, however package-private
	// types with type-safe accessors provide a convenient way for packages
	// to mediate access to their request-local data.
	Env map[interface{}]interface{}
}

C is a request-local context object which is threaded through all compliant middleware layers and given to the final request handler.

type Handler

type Handler interface {
	ServeHTTPC(C, http.ResponseWriter, *http.Request)
}

Handler is similar to net/http's http.Handler, but also accepts a Goji context object.

type HandlerFunc

type HandlerFunc func(C, http.ResponseWriter, *http.Request)

HandlerFunc is similar to net/http's http.HandlerFunc, but supports a context object. Implements both http.Handler and Handler.

func (HandlerFunc) ServeHTTP

func (h HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler, allowing HandlerFunc's to be used with net/http and other compliant routers. When used in this way, the underlying function will be passed an empty context.

func (HandlerFunc) ServeHTTPC

func (h HandlerFunc) ServeHTTPC(c C, w http.ResponseWriter, r *http.Request)

ServeHTTPC implements Handler.

type HandlerType added in v1.0.1

type HandlerType interface{}

HandlerType is the type of Handlers and types that Goji internally converts to Handler. In order to provide an expressive API, this type is an alias for interface{} that is named for the purposes of documentation, however only the following concrete types are accepted:

  • types that implement http.Handler
  • types that implement Handler
  • func(http.ResponseWriter, *http.Request)
  • func(web.C, http.ResponseWriter, *http.Request)

type Match added in v1.0.1

type Match struct {
	// Pattern is the Pattern that matched during routing. Will be nil if no
	// route matched (Handler will be set to the Mux's NotFound handler)
	Pattern Pattern
	// The Handler corresponding to the matched pattern.
	Handler Handler
}

Match is the type of routing matches. It is inserted into C.Env under MatchKey when the Mux.Router middleware is invoked. If MatchKey is present at route dispatch time, the Handler of the corresponding Match will be called instead of performing routing as usual.

By computing a Match and inserting it into the Goji environment as part of a middleware stack (see Mux.Router, for instance), it is possible to customize Goji's routing behavior or replace it entirely.

func GetMatch added in v1.0.1

func GetMatch(c C) Match

GetMatch returns the Match stored in the Goji environment, or an empty Match if none exists (valid Matches always have a Handler property).

func (Match) RawHandler added in v1.0.1

func (m Match) RawHandler() HandlerType

RawHandler returns the HandlerType that was originally passed to the HTTP method functions (Get, Post, etc.).

func (Match) RawPattern added in v1.0.1

func (m Match) RawPattern() PatternType

RawPattern returns the PatternType that was originally passed to ParsePattern or any of the HTTP method functions (Get, Post, etc.).

type MiddlewareType added in v1.0.1

type MiddlewareType interface{}

MiddlewareType is the type of Goji middleware. In order to provide an expressive API, this type is an alias for interface{} that is named for the purposes of documentation, however only the following concrete types are accepted:

  • func(http.Handler) http.Handler
  • func(*web.C, http.Handler) http.Handler

type Mux

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

Mux is an HTTP multiplexer, much like net/http's ServeMux. It functions as both a middleware stack and as an HTTP router.

Middleware provide a great abstraction for actions that must be performed on every request, such as request logging and authentication. To append, insert, and remove middleware, you can call the Use, Insert, and Abandon functions respectively.

Routes may be added using any of the HTTP verb functions (Get, Post, etc.), or through the generic Handle function. Goji's routing algorithm is very simple: routes are processed in the order they are added, and the first matching route will be executed. Routes match if their HTTP method and Pattern both match.

func New

func New() *Mux

New creates a new Mux without any routes or middleware.

func (*Mux) Abandon

func (m *Mux) Abandon(middleware MiddlewareType) error

Abandon removes the given middleware from the middleware stack. Returns an error if no such middleware can be found.

If the name of the middleware to delete is ambiguous, the first (outermost) one is chosen. It is illegal to call this function concurrently with active requests.

func (*Mux) Compile

func (m *Mux) Compile()

Compile compiles the list of routes into bytecode. This only needs to be done once after all the routes have been added, and will be called automatically for you (at some performance cost on the first request) if you do not call it explicitly.

func (*Mux) Connect

func (m *Mux) Connect(pattern PatternType, handler HandlerType)

Connect dispatches to the given handler when the pattern matches and the HTTP method is CONNECT.

func (*Mux) Delete

func (m *Mux) Delete(pattern PatternType, handler HandlerType)

Delete dispatches to the given handler when the pattern matches and the HTTP method is DELETE.

func (*Mux) Get

func (m *Mux) Get(pattern PatternType, handler HandlerType)

Get dispatches to the given handler when the pattern matches and the HTTP method is GET.

All GET handlers also transparently serve HEAD requests, since net/http will take care of all the fiddly bits for you. If you wish to provide an alternate implementation of HEAD, you should add a handler explicitly and place it above your GET handler.

func (*Mux) Handle

func (m *Mux) Handle(pattern PatternType, handler HandlerType)

Handle dispatches to the given handler when the pattern matches, regardless of HTTP method.

This method is commonly used to implement sub-routing: an admin application, for instance, can expose a single handler that is attached to the main Mux by calling Handle("/admin/*", adminHandler) or similar. Note that this function doesn't strip this prefix from the path before forwarding it on (e.g., the handler will see the full path, including the "/admin/" part), but this functionality can easily be performed by an extra middleware layer.

func (*Mux) Head

func (m *Mux) Head(pattern PatternType, handler HandlerType)

Head dispatches to the given handler when the pattern matches and the HTTP method is HEAD.

func (*Mux) Insert

func (m *Mux) Insert(middleware, before MiddlewareType) error

Insert inserts the given middleware immediately before a given existing middleware in the stack. Returns an error if "before" cannot be found in the current stack.

No attempt is made to enforce the uniqueness of middlewares. If the insertion point is ambiguous, the first (outermost) one is chosen. It is illegal to call this function concurrently with active requests.

func (*Mux) NotFound

func (m *Mux) NotFound(handler HandlerType)

NotFound sets the fallback (i.e., 404) handler for this mux.

As a convenience, the context environment variable "goji.web.validMethods" (also available as the constant ValidMethodsKey) will be set to the list of HTTP methods that could have been routed had they been provided on an otherwise identical request.

func (*Mux) Options

func (m *Mux) Options(pattern PatternType, handler HandlerType)

Options dispatches to the given handler when the pattern matches and the HTTP method is OPTIONS.

func (*Mux) Patch

func (m *Mux) Patch(pattern PatternType, handler HandlerType)

Patch dispatches to the given handler when the pattern matches and the HTTP method is PATCH.

func (*Mux) Post

func (m *Mux) Post(pattern PatternType, handler HandlerType)

Post dispatches to the given handler when the pattern matches and the HTTP method is POST.

func (*Mux) Put

func (m *Mux) Put(pattern PatternType, handler HandlerType)

Put dispatches to the given handler when the pattern matches and the HTTP method is PUT.

func (*Mux) Router added in v1.0.1

func (m *Mux) Router(c *C, h http.Handler) http.Handler

Router is a middleware that performs routing and stores the resulting Match in Goji's environment. If a routing Match is present at the end of the middleware stack, that Match is used instead of re-routing.

This middleware is especially useful to create post-routing middleware, e.g. a request logger which prints which pattern or handler was selected, or an authentication middleware which only applies to certain routes.

If you use nested Muxes with explicit routing, you should be aware that the explicit routing information set by an outer Mux can be picked up by an inner Mux, inadvertently causing an infinite routing loop. If you use both explicit routing and nested Muxes, you should be sure to unset MatchKey before the inner Mux performs routing (or attach a Router to the inner Mux as well).

func (*Mux) ServeHTTP

func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP processes HTTP requests. Satisfies net/http.Handler.

func (*Mux) ServeHTTPC

func (m *Mux) ServeHTTPC(c C, w http.ResponseWriter, r *http.Request)

ServeHTTPC creates a context dependent request with the given Mux. Satisfies the Handler interface.

func (*Mux) Trace

func (m *Mux) Trace(pattern PatternType, handler HandlerType)

Trace dispatches to the given handler when the pattern matches and the HTTP method is TRACE.

func (*Mux) Use

func (m *Mux) Use(middleware MiddlewareType)

Use appends the given middleware to the middleware stack.

No attempt is made to enforce the uniqueness of middlewares. It is illegal to call this function concurrently with active requests.

type Pattern

type Pattern interface {
	// In practice, most real-world routes have a string prefix that can be
	// used to quickly determine if a pattern is an eligible match. The
	// router uses the result of this function to optimize away calls to the
	// full Match function, which is likely much more expensive to compute.
	// If your Pattern does not support prefixes, this function should
	// return the empty string.
	Prefix() string
	// Returns true if the request satisfies the pattern. This function is
	// free to examine both the request and the context to make this
	// decision. Match should not modify either argument, and since it will
	// potentially be called several times over the course of matching a
	// request, it should be reasonably efficient.
	Match(r *http.Request, c *C) bool
	// Run the pattern on the request and context, modifying the context as
	// necessary to bind URL parameters or other parsed state.
	Run(r *http.Request, c *C)
}

A Pattern determines whether or not a given request matches some criteria. They are often used in routes, which are essentially (pattern, methodSet, handler) tuples. If the method and pattern match, the given handler is used.

Built-in implementations of this interface are used to implement regular expression and string matching.

func ParsePattern added in v0.8.2

func ParsePattern(raw PatternType) Pattern

ParsePattern is used internally by Goji to parse route patterns. It is exposed publicly to make it easier to write thin wrappers around the built-in Pattern implementations.

ParsePattern fatally exits (using log.Fatalf) if it is passed a value of an unexpected type (see the documentation for PatternType for a list of which types are accepted). It is the caller's responsibility to ensure that ParsePattern is called in a type-safe manner.

type PatternType added in v1.0.1

type PatternType interface{}

PatternType is the type denoting Patterns and types that Goji internally converts to Pattern (via the ParsePattern function). In order to provide an expressive API, this type is an alias for interface{} that is named for the purposes of documentation, however only the following concrete types are accepted:

  • types that implement Pattern

  • string, which is interpreted as a Sinatra-like URL pattern. In particular, the following syntax is recognized:

  • a path segment starting with a colon will match any string placed at that position. e.g., "/:name" will match "/carl", binding "name" to "carl".

  • a pattern ending with "/*" will match any route with that prefix. For instance, the pattern "/u/:name/*" will match "/u/carl/" and "/u/carl/projects/123", but not "/u/carl" (because there is no trailing slash). In addition to any names bound in the pattern, the special key "*" is bound to the unmatched tail of the match, but including the leading "/". So for the two matching examples above, "*" would be bound to "/" and "/projects/123" respectively. Unlike http.ServeMux's patterns, string patterns support neither the "rooted subtree" behavior nor Host-specific routes. Users who require either of these features are encouraged to compose package http's mux with the mux provided by this package.

  • regexp.Regexp, which is assumed to be a Perl-style regular expression that is anchored on the left (i.e., the beginning of the string). If your regular expression is not anchored on the left, a hopefully-identical left-anchored regular expression will be created and used instead.

    Capturing groups will be converted into bound URL parameters in URLParams. If the capturing group is named, that name will be used; otherwise the special identifiers "$1", "$2", etc. will be used.

Directories

Path Synopsis
Package middleware provides several standard middleware implementations.
Package middleware provides several standard middleware implementations.
Package mutil contains various functions that are helpful when writing http middleware.
Package mutil contains various functions that are helpful when writing http middleware.

Jump to

Keyboard shortcuts

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