router

package module
v0.0.0-...-4d32ace Latest Latest
Warning

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

Go to latest
Published: Jun 27, 2014 License: MIT Imports: 7 Imported by: 7

README

Router

Package router is deprecated, please use https://github.com/tedsuo/rata instead.

A router with Pat-style path patterns.

API Docs: https://godoc.org/github.com/tedsuo/router

Package router provides three things: Routes, a Router, and a RequestGenerator.

Routes are structs that define which Method and Path each associated http handler should respond to. Unlike many router implementations, the routes and the handlers are defined separately. This allows for the routes to be reused in multiple contexts. For example, a proxy server and a backend server can be created by having one set of Routes, but two sets of Handlers (one handler that proxies, another that serves the request). Likewise, your client code can use the routes with the RequestGenerator to create requests that use the same routes. Then, if the routes change, unit tests in the client and proxy service will warn you of the problem. This contract helps components stay in sync while relying less on integration tests.

For example, let's imagine that you want to implement a "pet" resource that allows you to view, create, update, and delete which pets people own. Also, you would like to include the owner_id and pet_id as part of the URL path.

First off, the routes might look like this:

  petRoutes := router.Routes{
    {Handler: "get_pet",    Method: "GET",    Path: "/people/:owner_id/pets/:pet_id"},
    {Handler: "create_pet", Method: "POST",   Path: "/people/:owner_id/pets"},
    {Handler: "update_pet", Method: "PUT",    Path: "/people/:owner_id/pets/:pet_id"},
    {Handler: "delete_pet", Method: "DELETE", Path: "/people/:owner_id/pets/:pet_id"},
  }

On the server, create a matching set of http handlers, one for each route:

  petHandlers := router.Handlers{
    "get_pet":    newGetPetHandler(),
    "create_pet": newCreatePetHandler(),
    "update_pet": newUpdatePetHandler(),
    "delete_pet": newDeletePetHandler()
  }

You can create a router by mixing the routes and handlers together:

  routerHandler, err := router.NewRouter(petRoutes, petHandlers)
  if err != nil {
    panic(err)
  }

  // The router is just an http.Handler, so it can be used to create a server in the usual fashion:
  server := httptest.NewServer(routerHandler)

Meanwhile, on the client side, you can create a request generator:

  requestGenerator := router.NewRequestGenerator(server.URL, petRoutes)

  // You can use the request generator to ensure you are creating a valid request:
  req, err := requestGenerator.RequestForHandler("get_pet", router.Params{"owner_id": "123", "pet_id": "5"}, nil)

  // The generated request can be used like any other http.Request object:
  res, err := http.DefaultClient.Do(req)

Documentation

Overview

Package router is deprecated, please use https://github.com/tedsuo/rata instead.

Package router provides three things: Routes, a Router, and a RequestGenerator.

Routes are structs that define which Method and Path each associated http handler should respond to. Unlike many router implementations, the routes and the handlers are defined separately. This allows for the routes to be reused in multiple contexts. For example, a proxy server and a backend server can be created by having one set of Routes, but two sets of Handlers (one handler that proxies, another that serves the request). Likewise, your client code can use the routes with the RequestGenerator to create requests that use the same routes. Then, if the routes change, unit tests in the client and proxy service will warn you of the problem. This contract helps components stay in sync while relying less on integration tests.

For example, let's imagine that you want to implement a "pet" resource that allows you to view, create, update, and delete which pets people own. Also, you would like to include the owner_id and pet_id as part of the URL path.

First off, the routes might look like this:

petRoutes := router.Routes{
  {Handler: "get_pet",    Method: "GET",    Path: "/people/:owner_id/pets/:pet_id"},
  {Handler: "create_pet", Method: "POST",   Path: "/people/:owner_id/pets"},
  {Handler: "update_pet", Method: "PUT",    Path: "/people/:owner_id/pets/:pet_id"},
  {Handler: "delete_pet", Method: "DELETE", Path: "/people/:owner_id/pets/:pet_id"},
}

On the server, create a matching set of http handlers, one for each route:

handlers := router.Handlers{
  "get_pet":    newGetPetHandler(),
  "create_pet": newCreatePetHandler(),
  "update_pet": newUpdatePetHandler(),
  "delete_pet": newDeletePetHandler()
}

You can create a router by mixing the routes and handlers together:

routerHandler, err := router.NewRouter(petRoutes, handlers)
if err != nil {
  panic(err)
}

The router is just an http.Handler, so it can be used to create a server in the usual fashion:

server := httptest.NewServer(routerHandler)

Meanwhile, on the client side, you can create a request generator:

requestGenerator := router.NewRequestGenerator(server.URL, petRoutes)

You can use the request generator to ensure you are creating a valid request:

req, err := requestGenerator.RequestForHandler("get_pet", router.Params{"owner_id": "123", "pet_id": "5"}, nil)

The generated request can be used like any other http.Request object:

res, err := http.DefaultClient.Do(req)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewRouter

func NewRouter(routes Routes, handlers Handlers) (http.Handler, error)

NewRouter combines a set of Routes with their corresponding Handlers to produce a http request multiplexer (AKA a "router").

Types

type Handlers

type Handlers map[string]http.Handler

Handlers map Handler keys to http.Handler objects. The Handler key is used to then match the Handler to the appropriate Route in the Router.

type Params

type Params map[string]string

Params map path keys to values. For example, if your route has the path pattern:

/person/:person_id/pets/:pet_type

Then a correct Params map would lool like:

router.Params{
  "person_id": "123",
  "pet_type": "cats",
}

type RequestGenerator

type RequestGenerator struct {
	Header http.Header
	// contains filtered or unexported fields
}

RequestGenerator creates http.Request objects with the correct path and method pre-filled for the given route object. You can also set the the host and, optionally, any headers you would like included with every request.

func NewRequestGenerator

func NewRequestGenerator(host string, routes Routes) *RequestGenerator

NewRequestGenerator creates a RequestGenerator for a given host and route set. Host is of the form "http://example.com".

func (*RequestGenerator) RequestForHandler

func (r *RequestGenerator) RequestForHandler(
	handler string,
	params Params,
	body io.Reader,
) (*http.Request, error)

RequestForHandler creates a new http Request for the matching handler. If the request cannot be created, either because the handler does not exist or because the given params do not match the params the route requires, then RequestForHandler returns an error.

type Route

type Route struct {
	// Handler is a key specifying which HTTP handler the router
	// should associate with the endpoint at runtime.
	Handler string
	// Method is one of the following: GET,PUT,POST,DELETE
	Method string
	// Path contains a path pattern
	Path string
}

A Route defines properties of an HTTP endpoint. At runtime, the router will associate each Route with a http.Handler object, and use the Route properties to determine which Handler should be invoked.

Currently, the properties used for matching are Method and Path.

Method can be one of the following:

GET PUT POST DELETE

Path conforms to Pat-style pattern matching. The following docs are taken from http://godoc.org/github.com/bmizerany/pat#PatternServeMux

Path Patterns may contain literals or captures. Capture names start with a colon and consist of letters A-Z, a-z, _, and 0-9. The rest of the pattern matches literally. The portion of the URL matching each name ends with an occurrence of the character in the pattern immediately following the name, or a /, whichever comes first. It is possible for a name to match the empty string.

Example pattern with one capture:

/hello/:name

Will match:

/hello/blake
/hello/keith

Will not match:

/hello/blake/
/hello/blake/foo
/foo
/foo/bar

Example 2:

/hello/:name/

Will match:

/hello/blake/
/hello/keith/foo
/hello/blake
/hello/keith

Will not match:

/foo
/foo/bar

func (Route) PathWithParams

func (r Route) PathWithParams(params Params) (string, error)

PathWithParams combines the route's path pattern with a Params map to produce a valid path.

type Routes

type Routes []Route

Routes is a Route collection.

func (Routes) PathForHandler

func (r Routes) PathForHandler(handler string, params Params) (string, error)

PathForHandler looks up a Route by it's Handler key and computes it's path with a given Params map.

func (Routes) RouteForHandler

func (r Routes) RouteForHandler(handler string) (Route, bool)

RouteForHandler looks up a Route by it's Handler key.

func (Routes) Router

func (r Routes) Router(handlers Handlers) (http.Handler, error)

Router is deprecated, please use router.NewRouter() instead

Jump to

Keyboard shortcuts

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