README

Goji

GoDoc Build Status

Goji is a HTTP request multiplexer, similar to net/http.ServeMux. It compares incoming requests to a list of registered Patterns, and dispatches to the Handler that corresponds to the first matching Pattern. Goji also supports Middleware (composable shared functionality applied to every request) and uses the de facto standard x/net/context to store request-scoped values.

Quick Start

package main

import (
        "fmt"
        "net/http"

        "goji.io"
        "goji.io/pat"
        "golang.org/x/net/context"
)

func hello(ctx context.Context, w http.ResponseWriter, r *http.Request) {
        name := pat.Param(ctx, "name")
        fmt.Fprintf(w, "Hello, %s!", name)
}

func main() {
        mux := goji.NewMux()
        mux.HandleFuncC(pat.Get("/hello/:name"), hello)

        http.ListenAndServe("localhost:8000", mux)
}

Please refer to Goji's GoDoc Documentation for a full API reference.

Stability

Goji's API is stable, and guarantees to never break compatibility with existing code (under similar rules to the Go project's guidelines). Goji is suitable for use in production.

One possible exception to the above compatibility guarantees surrounds the inclusion of the x/net/context package in the standard library for Go 1.7. When this happens, Goji may switch its package imports to use the standard library's version of the package. Note that, while this is a backwards incompatible change, the impact on clients is expected to be minimal: applications will simply have to change the import path of the context package. More discussion about this migration can be found on the Goji mailing list.

Community / Contributing

Goji maintains a mailing list, gojiberries, where you should feel welcome to ask questions about the project (no matter how simple!), to announce projects or libraries built on top of Goji, or to talk about Goji more generally. Goji's author (Carl Jackson) also loves to hear from users directly at his personal email address, which is available on his GitHub profile page.

Contributions to Goji are welcome, however please be advised that due to Goji's stability guarantees interface changes are unlikely to be accepted.

All interactions in the Goji community will be held to the high standard of the broader Go community's Code of Conduct.

Expand ▾ Collapse ▴

Documentation

Overview

Package goji is a minimalistic and flexible HTTP request multiplexer.

Goji itself has very few features: it is first and foremost a standard set of interfaces for writing web applications. Several subpackages are distributed with Goji to provide standard production-ready implementations of several of the interfaces, however users are also encouraged to implement the interfaces on their own, especially if their needs are unusual.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Handler

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

Handler is a context-aware variant of net/http.Handler. It has the same semantics as http.Handler, except that a request-scoped context is additionally passed to the handler function.

type HandlerFunc

type HandlerFunc func(context.Context, http.ResponseWriter, *http.Request)

HandlerFunc is a context-aware variant of net/http.HandlerFunc. It has the same semantics as http.HandlerFunc, except that a request-scoped context is additionally passed to the function.

HandlerFunc implements both the Handler and http.Handler interfaces.

func (HandlerFunc) ServeHTTP

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

ServeHTTP implements net/http.Handler. It calls the underlying function with a context of context.TODO in order to ease the conversion of non-context-aware Handlers to context-aware ones using static analysis.

func (HandlerFunc) ServeHTTPC

func (h HandlerFunc) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request)

ServeHTTPC implements Handler.

type Mux

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

Mux is a HTTP multiplexer / router similar to net/http.ServeMux.

Muxes multiplex traffic between many Handlers by selecting the first applicable Pattern. They then call a common middleware stack, finally passing control to the selected Handler. See the documentation on the Handle function for more information about how routing is performed, the documentation on the Pattern type for more information about request matching, and the documentation for the Use method for more about middleware.

Muxes cannot be configured concurrently from multiple goroutines, nor can they be configured concurrently with requests.

func NewMux

func NewMux() *Mux

NewMux returns a new Mux with no configured middleware or routes.

func SubMux

func SubMux() *Mux

SubMux returns a new Mux with no configured middleware or routes, and which inherits routing information from the passed context. This is especially useful when using one Mux as a Handler registered to another "parent" Mux.

For example, a common pattern is to organize applications in a way that mirrors the structure of its URLs: a photo-sharing site might have URLs that start with "/users/" and URLs that start with "/albums/", and might be organized using three Muxes:

root := NewMux()
users := SubMux()
root.HandleC(pat.New("/users/*"), users)
albums := SubMux()
root.HandleC(pat.New("/albums/*"), albums)

// e.g., GET /users/carl
users.HandleC(pat.Get("/:name"), renderProfile)
// e.g., POST /albums/
albums.HandleC(pat.Post("/"), newAlbum)

func (*Mux) Handle

func (m *Mux) Handle(p Pattern, h http.Handler)

Handle adds a new route to the Mux. Requests that match the given Pattern will be dispatched to the given http.Handler. If the http.Handler also supports Handler, that interface will be used instead.

Routing is performed in the order in which routes are added: the first route with a matching Pattern will be used. In particular, Goji guarantees that routing is performed in a manner that is indistinguishable from the following algorithm:

// Assume routes is a slice that every call to Handle appends to
for route := range routes {
	// For performance, Patterns can opt out of this call to Match.
	// See the documentation for Pattern for more.
	if ctx2 := route.pattern.Match(ctx, r); ctx2 != nil {
		route.handler.ServeHTTPC(ctx2, w, r)
		break
	}
}

It is not safe to concurrently register routes from multiple goroutines, or to register routes concurrently with requests.

func (*Mux) HandleC

func (m *Mux) HandleC(p Pattern, h Handler)

HandleC adds a new context-aware route to the Mux. See the documentation for Handle for more information about the semantics of routing.

It is not safe to concurrently register routes from multiple goroutines, or to register routes concurrently with requests.

func (*Mux) HandleFunc

func (m *Mux) HandleFunc(p Pattern, h func(http.ResponseWriter, *http.Request))

HandleFunc adds a new route to the Mux. It is equivalent to calling Handle on a handler wrapped with http.HandlerFunc, and is provided only for convenience.

func (*Mux) HandleFuncC

func (m *Mux) HandleFuncC(p Pattern, h func(context.Context, http.ResponseWriter, *http.Request))

HandleFuncC adds a new context-aware route to the Mux. It is equivalent to calling HandleC on a handler wrapped with HandlerFunc, and is provided for convenience.

func (*Mux) ServeHTTP

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

ServeHTTP implements net/http.Handler. It uses context.TODO as the root context in order to ease the conversion of non-context-aware Handlers to context-aware ones using static analysis.

Users who know that their mux sits at the top of the request hierarchy should consider creating a small helper http.Handler that calls this Mux's ServeHTTPC function with context.Background.

func (*Mux) ServeHTTPC

func (m *Mux) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request)

ServeHTTPC implements Handler.

func (*Mux) Use

func (m *Mux) Use(middleware func(http.Handler) http.Handler)

Use appends a middleware to the Mux's middleware stack.

Middleware are composable pieces of functionality that augment Handlers. Common examples of middleware include request loggers, authentication checkers, and metrics gatherers.

Middleware are evaluated in the reverse order in which they were added, but the resulting Handlers execute in "normal" order (i.e., the Handler returned by the first Middleware to be added gets called first).

For instance, given middleware A, B, and C, added in that order, Goji will behave similarly to this snippet:

augmentedHandler := A(B(C(yourHandler)))
augmentedHandler.ServeHTTPC(ctx, w, r)

Assuming each of A, B, and C look something like this:

func A(inner goji.Handler) goji.Handler {
	log.Print("A: called")
	mw := func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
		log.Print("A: before")
		inner.ServeHTTPC(ctx, w, r)
		log.Print("A: after")
	}
	return goji.HandlerFunc(mw)
}

we'd expect to see the following in the log:

C: called
B: called
A: called
---
A: before
B: before
C: before
yourHandler: called
C: after
B: after
A: after

Note that augmentedHandler may be called many times. Put another way, you will see many invocations of the portion of the log below the divider, and perhaps only see the portion above the divider a single time. Also note that as an implementation detail, net/http-style middleware will be called once per request, even though the Goji-style middleware around them might only ever be called a single time.

Middleware in Goji is called after routing has been performed. Therefore it is possible to examine any routing information placed into the context by Patterns, or to view or modify the Handler that will be routed to. Middleware authors should read the documentation for the "middleware" subpackage for more information about how this is done.

The http.Handler returned by the given middleware must be safe for concurrent use by multiple goroutines. It is not safe to concurrently register middleware from multiple goroutines, or to register middleware concurrently with requests.

func (*Mux) UseC

func (m *Mux) UseC(middleware func(Handler) Handler)

UseC appends a context-aware middleware to the Mux's middleware stack. See the documentation for Use for more information about the semantics of middleware.

The Handler returned by the given middleware must be safe for concurrent use by multiple goroutines. It is not safe to concurrently register middleware from multiple goroutines, or to register middleware concurrently with requests.

type Pattern

type Pattern interface {
	// Match examines the request and request context to determine if the
	// request is a match. If so, it returns a non-nil context.Context
	// (likely one derived from the input Context, and perhaps simply the
	// input Context unchanged). The returned context may be used to store
	// request-scoped data, such as variables extracted from the Request.
	//
	// Match must not mutate the passed request.
	Match(context.Context, *http.Request) context.Context
}

Pattern determines whether a given request matches some criteria. Goji users looking for a concrete type that implements this interface should consider Goji's "pat" sub-package, which implements a small domain specific language for HTTP routing.

Patterns typically only examine a small portion of incoming requests, most commonly the HTTP method and the URL's RawPath. As an optimization, Goji can elide calls to your Pattern for requests it knows cannot match. Pattern authors who wish to take advantage of this functionality (and in some cases an asymptotic performance improvement) can augment their Pattern implementations with any of the following methods:

// HTTPMethods returns a set of HTTP methods that this Pattern matches,
// or nil if it's not possible to determine which HTTP methods might be
// matched. Put another way, requests with HTTP methods not in the
// returned set are guaranteed to never match this Pattern.
HTTPMethods() map[string]struct{}

// PathPrefix returns a string which all RawPaths that match this
// Pattern must have as a prefix. Put another way, requests with
// RawPaths that do not contain the returned string as a prefix are
// guaranteed to never match this Pattern.
PathPrefix() string

The presence or lack of these performance improvements should be viewed as an implementation detail and are not part of Goji's API compatibility guarantee. It is the responsibility of Pattern authors to ensure that their Match function always returns correct results, even if these optimizations are not performed.

All operations on Patterns must be safe for concurrent use by multiple goroutines.

Directories

Path Synopsis
internal Package internal is a private package that allows Goji to expose a less confusing interface to its users.
middleware Package middleware contains utilities for Goji Middleware authors.
pat Package pat is a URL-matching domain-specific language for Goji.
pattern Package pattern contains utilities for Goji Pattern authors.