router

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Jul 20, 2021 License: BSD-3-Clause Imports: 12 Imported by: 0

README

router

Router is a HTTP router for Golang. It's built on httprouter and takes inspiration from labstack/echo, but with reduced complexity and easier data binding.

The data binding is made easier by specifying your input as a parameter to your function

Example:

type someType struct {
	A string `json:"a"`
	B int    `json:"b"`
}

func handlePOST(c *router.Context, input someType) error {
	fmt.Println(input)
	return c.NoContent(200)
}
Why make data binding shorter?

Many applications read, bind and validate data for most calls. In Echo this could mean adding boilerplate code to every call. This extra boilerplate code can make your code significantly longer and very hard to read.

func handlePOST(c *echo.Context) error {
	var input someType
	err := c.Bind(&input)
	if err != nil {
		return c.NoContent(http.StatusBadRequest)
	}
	err = c.Validate(input)
	if err != nil {
		return c.NoContent(http.StatusBadRequest)
	}

	// Your actual code
}

In router you define your code to read, bind and validate the input once, and it applies to every POST, PATCH and PUT call.

What about the performance of dynamic parameters?

While using dynamic parameters takes a bit of extra processing, this barely has any impact on performance. Router can still handle tens to hunderds of thousands of requests per second.

How does middleware work?

Middleware works similar to most other routers. The dynamic parameters has no effect on middleware, input data is parsed after all middlewares and right before your handler.

Installation

go get git.fuyu.moe/Fuyu/router

Getting started

package main

import "git.fuyu.moe/Fuyu/router"

func main() {
	// Create a router instance
	r := router.New()
	
	// Add routes
	r.GET(`/`, yourGetFunc)
	r.POST(`/`, yourPostFunc)
	
	// Start router
	panic(r.Start(`127.0.0.1:8080`))
}

Advice

Configuration

For a serious project you should set r.Reader, r.ErrorHandler, r.NotFoundHandler, and r.MethodNotAllowedHandler.

Templating

You can set r.Renderer and call c.Render(code, tmplName, data) in your handlers

Examples

package main

import (
	"fmt"
	"time"

	"git.fuyu.moe/Fuyu/router"
)

type product struct {
	Name string `json:"name"`
}

func main() {
	r := router.New()
	r.Use(accessLog)

	r.GET(`/hello`, hello)

	a := r.Group(`/api`, gandalf)
	a.POST(`/product`, createProduct)
	a.PATCH(`/product/:id`, updateProduct)
	a.POST(`/logout`, logout)

	r.Start(`:8080`)
}

func accessLog(next router.Handle) router.Handle {
	return func(c *router.Context) error {
		t := time.Now()
		err := next(c)

		fmt.Println(c.Request.Method, c.Request.URL.Path, c.Request.RemoteAddr, t, time.Since(t))

		return err
	}
}

func gandalf(next router.Handle) router.Handle {
	youShallPass := false
	return func(c *router.Context) error {
		if !youShallPass {
			return c.String(401, `You shall not pass`)
		}

		return next(c)
	}
}

func hello(c *router.Context) error {
	return c.String(200, `Hello`)
}

func createProduct(c *router.Context, p product) error {
	return c.JSON(200, p)
}

func updateProduct(c *router.Context, p product) error {
	productID := c.Param(`id`)
	return c.String(200, fmt.Sprintf(
		`ProductID %d new name %s`, productID, p.Name,
	))
}

func logout(c *router.Context) error {
	return c.String(200, `logout`)
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Context

type Context struct {
	Request  *http.Request
	Response http.ResponseWriter
	Param    func(string) string
	// contains filtered or unexported fields
}

Context is passed to handlers and middlewares

func NewContext added in v0.1.5

func NewContext(router *Router, res http.ResponseWriter, req *http.Request, param httprouter.Params) *Context

NewContext creates a new context, this function is only exported for use in tests

func (*Context) Bytes

func (c *Context) Bytes(code int, b []byte) error

Bytes returns the given status code and writes the bytes to the body

func (*Context) Get

func (c *Context) Get(key string) interface{}

Get retrieves a value from the context.

func (*Context) JSON

func (c *Context) JSON(code int, data interface{}) error

JSON returns the given status code and writes JSON to the body

func (*Context) NoContent

func (c *Context) NoContent(code int) error

NoContent returns the given status code without writing anything to the body

func (*Context) QueryParam added in v0.1.1

func (c *Context) QueryParam(param string) string

QueryParam returns the specified parameter from the query string. Returns an empty string if it doesn't exist. Returns the first parameter if multiple instances exist

func (*Context) RealIP added in v0.1.4

func (c *Context) RealIP() string

RealIP uses proxy headers for the real ip, if none exist the IP of the current connection is returned

func (*Context) Redirect added in v0.1.1

func (c *Context) Redirect(code int, url string) error

Redirect sends a redirect to the client

func (*Context) Render

func (c *Context) Render(code int, template string, data interface{}) error

Render renders a templating using the Renderer set in router

func (*Context) Set

func (c *Context) Set(key string, value interface{})

Set sets a value in the context. Set is not safe to be used concurrently

func (*Context) StatusText added in v0.0.3

func (c *Context) StatusText(code int) error

StatusText returns the given status code with the matching status text

func (*Context) String

func (c *Context) String(code int, s string) error

String returns the given status code and writes the string to the body

type ErrorHandle

type ErrorHandle func(*Context, interface{})

ErrorHandle handles a request

type Group

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

Group is a router group with a shared prefix and set of middlewares

func (*Group) DELETE

func (g *Group) DELETE(path string, handle Handle, middleware ...Middleware)

DELETE adds a DELETE route

func (*Group) GET

func (g *Group) GET(path string, handle Handle, middleware ...Middleware)

GET adds a GET route

func (*Group) Group

func (g *Group) Group(prefix string, middleware ...Middleware) *Group

Group creates a new router group with a shared prefix and set of middlewares

func (*Group) HEAD

func (g *Group) HEAD(path string, handle Handle, middleware ...Middleware)

HEAD adds a HEAD route

func (*Group) OPTIONS

func (g *Group) OPTIONS(path string, handle Handle, middleware ...Middleware)

OPTIONS adds a OPTIONS route

func (*Group) PATCH

func (g *Group) PATCH(path string, handle interface{}, middleware ...Middleware)

PATCH adds a PATCH route

func (*Group) POST

func (g *Group) POST(path string, handle interface{}, middleware ...Middleware)

POST adds a POST route

func (*Group) PUT

func (g *Group) PUT(path string, handle interface{}, middleware ...Middleware)

PUT adds a PUT route

type Handle

type Handle = func(*Context) error

Handle handles a request

type Middleware

type Middleware func(Handle) Handle

Middleware is a function that runs before your route, it gets the next handler as a parameter

type Reader

type Reader func(c *Context, dst interface{}) (bool, error)

Reader reads input to dst, returns true if successful

type Renderer

type Renderer interface {
	Render(w io.Writer, template string, data interface{}, c *Context) error
}

Renderer renders a template

type Router

type Router struct {
	Reader   Reader
	Renderer Renderer

	NotFoundHandler         Handle
	MethodNotAllowedHandler Handle
	ErrorHandler            ErrorHandle
	TrimTrailingSlashes     bool
	// contains filtered or unexported fields
}

Router is the router itself

func New

func New() *Router

New returns a new Router

func (*Router) DELETE

func (r *Router) DELETE(path string, handle Handle, middleware ...Middleware)

DELETE adds a DELETE route

func (*Router) GET

func (r *Router) GET(path string, handle Handle, middleware ...Middleware)

GET adds a GET route

func (*Router) Group

func (r *Router) Group(prefix string, middleware ...Middleware) *Group

Group creates a new router group with a shared prefix and set of middlewares

func (*Router) HEAD

func (r *Router) HEAD(path string, handle Handle, middleware ...Middleware)

HEAD adds a HEAD route

func (*Router) OPTIONS

func (r *Router) OPTIONS(path string, handle Handle, middleware ...Middleware)

OPTIONS adds a OPTIONS route

func (*Router) PATCH

func (r *Router) PATCH(path string, handle interface{}, middleware ...Middleware)

PATCH adds a PATCH route

func (*Router) POST

func (r *Router) POST(path string, handle interface{}, middleware ...Middleware)

POST adds a POST route

func (*Router) PUT

func (r *Router) PUT(path string, handle interface{}, middleware ...Middleware)

PUT adds a PUT route

func (*Router) Start

func (r *Router) Start(addr string) error

Start starts the web server and binds to the given address

func (*Router) StartTLS added in v0.1.2

func (r *Router) StartTLS(addr, certFile, keyFile string, conf *tls.Config) error

StartTLS starts a TLS web server using the given key, cert and config and binds to the given address

func (*Router) Stop added in v0.1.2

func (r *Router) Stop() error

Stop stops the web server

func (*Router) Use

func (r *Router) Use(m ...Middleware)

Use adds a global middleware

Jump to

Keyboard shortcuts

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