Geen omschrijving
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Wijnand Modderman-Lenstra 2298f60ac9 More sugar 3 jaren geleden
_examples Update example 3 jaren geleden
docgen Ported middlewares 3 jaren geleden
header Rewitten to 3 jaren geleden
middleware More sugar 3 jaren geleden
.drone.yml Be verbose 3 jaren geleden
.gitignore Ensure a route context is available 3 jaren geleden
.travis.yml Travis: Build examples 3 jaren geleden Update README, etc 3 jaren geleden Add Travis widget to README 3 jaren geleden
LICENSE Rewitten to 3 jaren geleden Ported middlewares 3 jaren geleden
chain.go Ported middlewares 3 jaren geleden
content.go Versioned package; Cleanups 3 jaren geleden
context.go Added NotFound 3 jaren geleden
mux.go Retrieve context from request context 3 jaren geleden
mux_test.go Versioned package; Cleanups 3 jaren geleden
param.go Versioned package; Cleanups 3 jaren geleden
phi.go Ported middlewares 3 jaren geleden
register.go Rewitten to 3 jaren geleden
render.go Convert Context to interface 3 jaren geleden
tree.go Versioned package; Cleanups 3 jaren geleden
tree_test.go Convert Context to interface 3 jaren geleden


GoDoc Widget Drone Widget Codebeat Widget

phi is a lightweight, idiomatic and composable router for building Go 1.7+ HTTP services. It’s especially good at helping you write large REST API services that are kept maintainable as your project grows and changes. phi is built on the new context package introduced in Go 1.7 to handle signaling, cancelation and request-scoped values across a handler chain.

The focus of the project has been to seek out an elegant and comfortable design for writing REST API servers, written during the development of the Pressly API service that powers our public API service and all of our client-side applications.

The key considerations of chi’s design are: project structure, maintainability, standard http handlers (stdlib-only), developer productivity, and deconstructing a large system into many small parts. The core router is quite small (less than 1000 LOC), but we’ve also included some useful/optional subpackages: middleware, render and docgen. We hope you enjoy it too!


  • Lightweight - cloc’d in <1000 LOC for the phi router
  • Fast - yes, see benchmarks
  • Designed for modular/composable APIs - middlewares, inline middlewares, route groups and subrouter mounting
  • Context control - built on new context package, providing value chaining, cancelations and timeouts
  • Robust - tested / used in production at, and many others
  • Doc generation - docgen auto-generates routing documentation from your source to JSON or Markdown
  • No external dependencies - plain ol’ Go 1.7+ stdlib + net/http



  • rest - REST APIs made easy, productive and maintainable
  • limits - Timeouts and Throttling
  • todos-resource - Struct routers/handlers, an example of another code layout style
  • versions - Demo of chi/render subpkg
  • fileserver - Easily serve static files


Here is a little preview of how routing looks like with phi. Also take a look at the generated routing docs in JSON (routes.json) and in Markdown (

import (
  phi ""

func main() {
  r := phi.NewRouter()

  // A good base middleware stack

  // When a client closes their connection midway through a request, the
  // http.CloseNotifier will cancel the request context (ctx).

  // Set a timeout value on the request context (ctx), that will signal
  // through ctx.Done() that the request has timed out and further
  // processing should be stopped.
  r.Use(middleware.Timeout(60 * time.Second))

  r.Get("/", func(w http.ResponseWriter, r *http.Request) {

  // RESTy routes for "articles" resource
  r.Route("/articles", func(r phi.Router) {
    r.With(paginate).Get("/", listArticles)  // GET /articles
    r.Post("/", createArticle)               // POST /articles
    r.Get("/search", searchArticles)         // GET /articles/search

    r.Route("/:articleID", func(r chi.Router) {
      r.Get("/", getArticle)                 // GET /articles/123
      r.Put("/", updateArticle)              // PUT /articles/123
      r.Delete("/", deleteArticle)           // DELETE /articles/123

  // Mount the admin sub-router
  r.Mount("/admin", adminRouter())

  http.ListenAndServe(":3333", r)

func ArticleCtx(next phi.Handler) phi.Handler {
  return http.HandlerFunc(func(ctx *phi.Context) {
    articleID := ctx.Param("articleID")
    article, err := dbGetArticle(articleID)
    if err != nil {
    ctx.SetValue("article", article)

func getArticle(ctx *phi.Context) {
  article, ok := ctx.Value("article").(*Article)
  if !ok {
    ctx.Error(nil, 422)
  ctx.Write([]byte(fmt.Sprintf("title:%s", article.Title)))

// A completely separate router for administrator routes
func adminRouter() phi.Handler {
  r := phi.NewRouter()
  r.Get("/", adminIndex)
  r.Get("/accounts", adminListAccounts)
  return r

func AdminOnly(next phi.Handler) phi.Handler {
  return http.HandlerFunc(func(ctx *phi.Context) {
    perm, ok := ctx.Value("acl.permission").(YourPermissionType)
    if !ok || !perm.IsAdmin() {
      ctx.Error(nil, 403)

Router design

Phi’s router is based on Chi’s router.

Chi’s router is based on a kind of Patricia Radix trie. Built on top of the tree is the Router interface:

// Router consisting of the core routing methods used by phi's Mux.
type Router interface {

	// Use appends one of more middlewares onto the Router stack.
	Use(middlewares ...func(Handler) Handler)

	// With adds inline middlewares for an endpoint handler.
	With(middlewares ...func(Handler) Handler) Router

	// Group adds a new inline-Router along the current routing
	// path, with a fresh middleware stack for the inline-Router.
	Group(fn func(r Router)) Router

	// Route mounts a sub-Router along a `pattern`` string.
	Route(pattern string, fn func(r Router)) Router

	// Mount attaches another Handler along ./pattern/*
	Mount(pattern string, h Handler)

	// Handle and HandleFunc adds routes for `pattern` that matches
	// all HTTP methods.
	Handle(pattern string, h Handler)
	HandleFunc(pattern string, h HandlerFunc)
  HTTPHandle(pattern string, h http.Handler)
  HTTPHandleFunc(pattern string, h http.HandlerFunc)

	// HTTP-method routing along `pattern`
	Connect(pattern string, h HandlerFunc)
	Delete(pattern string, h HandlerFunc)
	Get(pattern string, h HandlerFunc)
	Head(pattern string, h HandlerFunc)
	Options(pattern string, h HandlerFunc)
	Patch(pattern string, h HandlerFunc)
	Post(pattern string, h HandlerFunc)
	Put(pattern string, h HandlerFunc)
	Trace(pattern string, h HandlerFunc)

	// NotFound defines a handler to respond whenever a route could
	// not be found.
	NotFound(h HandlerFunc)

// Routes interface adds two methods for router traversal, which is also
// used by the `docgen` subpackage to generation documentation for Routers.
type Routes interface {
	// Routes returns the routing tree in an easily traversable structure.
	Routes() []Route

	// Middlewares returns the list of middlewares in use by the router.
	Middlewares() Middlewares

Each routing method accepts a URL pattern and chain of handlers. The URL pattern supports named params (ie. /users/:userID) and wildcards (ie. /admin/*).

Middleware handlers

// HTTP middleware setting a value on the request context
func Middleware(next Handler) Handler {
  return http.HandlerFunc(func(ctx *phi.Context) {
    ctx.SetValue("user", "123")

Request handlers

// HTTP handler accessing data from the request context.
func Handler(ctx *phi.Context) {
  user := ctx.Value("user").(string)
  ctx.Write([]byte(fmt.Sprintf("hi %s", user)))
// HTTP handler accessing the url routing parameters.
func CtxHandler(ctx *phi.Context) {
  userID := ctx.Param("userID") // from a route like /users/:userID

  key := ctx.Value("key").(string)

  ctx.Write([]byte(fmt.Sprintf("hi %v, %v", userID, key)))


Chi comes equipped with an optional middleware package, providing:

Middleware Description
RequestID Injects a request ID into the context of each request.
RealIP Sets a http.Request’s RemoteAddr to either X-Forwarded-For or X-Real-IP.
Logger Logs the start and end of each request with the elapsed processing time.
Recoverer Gracefully absorb panics and prints the stack trace.
NoCache Sets response headers to prevent clients from caching.
CloseNotify Signals to the request context when a client has closed their connection.
Timeout Signals to the request context when the timeout deadline is reached.
Throttle Puts a ceiling on the number of concurrent requests.
Compress Gzip compression for clients that accept compressed responses.
Profiler Easily attach net/http/pprof to your routers.
Slashes Strip and redirect slashes on routing paths.
WithValue Short-hand middleware to set a key/value on the request context.



We’ll be more than happy to see your contributions!


Copyright © 2016-present maze

Licensed under MIT License