GoDoc Version Build Status Coverage Status Go Report Card

YARF: Yet Another REST Framework

YARF is a fast micro-framework designed to build REST APIs and web services in a fast and simple way. Designed after Go's composition features, takes a new approach to write simple and DRY code.

Getting started

Here's a transcription from our examples/simple package. This is a very simple Hello World web application example.

package main

import (

// Define a simple resource
type Hello struct {

// Implement the GET method
func (h *Hello) Get(c *yarf.Context) error {
    c.Render("Hello world!")
    return nil

// Run app server on http://localhost:8080
func main() {
    y := yarf.New()
    y.Add("/", new(Hello))

For more code and examples demonstrating all YARF features, please refer to the 'examples' directory.


Struct composition based design

YARF resources are custom structs that act as handlers for HTTP methods. Each resource can implement one, several or all HTTP methods needed (GET, POST, DELETE, etc.). Resources are created using Go's struct composition and you only have to declare the yarf.Resource type into your own struct.


import ""

// Define a simple resource
type Hello struct {

// Implement the GET method
func (h *Hello) Get(c *yarf.Context) error {
    c.Render("Hello world!")
    return nil

Simple router

Using a strict match model, it matches exact URLs against resources for increased performance and clarity during routing. The routes supports parameters in the form '/:param'.

The route:


Will match:


But it won't match:


You can define optional parameters using multiple routes on the same Resource.

Route parameters

At this point you know how to define parameters in your routes using the /:param naming convention. Now you'll see how easy is to get these parameters by their name from your resources using the Context.Param() method.


For the route:


You can have this resource:

import ""

type Hello struct {

func (h *Hello) Get(c *yarf.Context) error {
    name := c.Param("name")

    c.Render("Hello, " + name)

    return nil

Route wildcards

When some extra freedom is needed on your routes, you can use a * as part of your routes to match anything where the wildcard is present.

The route:


Will match the routes


And so on...

You can also combine this with parameters inside the routes for extra complexity.

Catch-All wildcard

When using the * at the end of any route, the router will match everything from the wildcard and forward.

The route:


Will match:


And so on...

Note about the wildcard

The * can only be used by itself and it doesn't works for single character matching like in regex.

So the route:


Will NOT match:


The Context object is passed as a parameter to all Resource methods and contains all the information related to the ongoing request.

Check the Context docs for a reference of the object:

Middleware support

Middleware support is implemented in a similar way as Resources, by using composition.
Routes will be pre-filtered and post-filtered by Middleware handlers when they're inserted in the router.


import ""

// Define your middleware and composite yarf.Middleware
type HelloMiddleware struct {

// Implement only the PreDispatch method, PostDispatch not needed.
func (m *HelloMiddleware) PreDispatch(c *yarf.Context) error {
    c.Render("Hello from middleware! \n") // Render to response.

    return nil

// Insert your middlewares to the server
func main() {
    y := yarf.New()

    // Add middleware
    // Define routes
    // ...
    // ...
    // Start the server
Route groups

Routes can be grouped into a route prefix and handle their own middleware.

Nested groups

As routes can be grouped into a route prefix, other groups can be also grouped allowing for nested prefixes and middleware layers.


import ""

// Entry point of the executable application
// It runs a default server listening on http://localhost:8080
// URLs after configuration:
// http://localhost:8080
// http://localhost:8080/hello/:name
// http://localhost:8080/v2
// http://localhost:8080/v2/hello/:name
// http://localhost:8080/extra/v2
// http://localhost:8080/extra/v2/hello/:name
func main() {
    // Create a new empty YARF server
    y := yarf.New()

    // Create resources
    hello := new(Hello)
    hellov2 := new(HelloV2)

    // Add main resource to multiple routes at root level.
    y.Add("/", hello)
    y.Add("/hello/:name", hello)

    // Create /v2 prefix route group
    g := yarf.RouteGroup("/v2")

    // Add /v2/ routes to the group
    g.Add("/", hellov2)
    g.Add("/hello/:name", hellov2)

    // Use middleware only on the /v2/ group

    // Add group to Yarf routes

    // Create another group for nesting into it.
    n := yarf.RouteGroup("/extra")

    // Nest /v2 group into /extra/v2

    // Use another middleware only for this /extra/v2 group

    // Add group to Yarf

    // Start server listening on port 8080

Check the ./examples/routegroups demo for the complete working implementation.

Route caching

A route cache is enabled by default to improve dispatch speed, but sacrificing memory space. If you're running out of RAM memory and/or your app has too many possible routes that may not fit, you should disable the route cache.

To enable/disable the route cache, just set the UseCache flag of the Yarf object:

y := yarf.New()
y.UseCache = false
Chain and extend

Just use the Yarf object as any http.Handler on a chain. Set another http.Handler on the Yarf.Follow property to be followed in case this Yarf router can't match the request.

Here's an example on how to follow the request to a public file server:

package main 

import (

func main() {
    y := yarf.New()

    // Add some routes
    y.Add("/hello/:name", new(Hello))
    //... more routes here
    // Follow to file server
    y.Follow = http.FileServer(http.Dir("/var/www/public"))
    // Start the server
Custom NotFound error handler

You can handle all 404 errors returned by any resource/middleware during the request flow of a Yarf server. To do so, you only have to implement a function with the func(c *yarf.Context) signature and set it to your server's Yarf.NotFound property.

y := yarf.New()

// ...

y.NotFound = func(c *yarf.Context) {
    c.Render("This is a custom Not Found handler")

// ...


On initial benchmarks, the framework seems to perform very well compared with other similar frameworks. Even when there are faster frameworks, under high load conditions and thanks to the route caching method, YARF seems to perform as good or even better than the fastests that work better under simpler conditions.

Check the benchmarks repository to run your own:

HTTPS support

Support for running HTTPS server from the net/http package.

Using the default server
func main() {
    y := yarf.New()
    // Setup the app
    // ...
    // ...
    // Start https listening on port 443
    y.StartTLS(":443", certFile, keyFile)

Using a custom server
func main() {
    y := yarf.New()

    // Setup the app
    // ...
    // ...

    // Configure custom http server and set the yarf object as Handler.
    s := &http.Server{
        Addr:           ":443",
        Handler:        y,
        ReadTimeout:    10 * time.Second,
        WriteTimeout:   10 * time.Second,
        MaxHeaderBytes: 1 << 20,
    s.ListenAndServeTLS(certFile, keyFile)

Why another micro-framework?

Why not?

No, seriously, i've researched for small/fast frameworks in the past for a Go project that I was starting. I found several options, but at the same time, none seemed to suit me. Some of them make you write weird function wrappers to fit the net/http package style. Actually, most of them seem to be function-based handlers. While that's not wrong, I feel more comfortable with the resource-based design, and this I also feel aligns better with the spirit of REST.

In Yarf you create a resource struct that represents a REST resource and it has all HTTP methods available. No need to create different routes for GET/POST/DELETE/etc. methods.

By using composition, you don't need to wrap functions inside functions over and over again to implement simple things like middleware or extension to your methods. You can abuse composition to create a huge OO-like design for your business model without sacrifying performance and code readability.

Even while the code style differs from the net/http package, the framework is fully compatible with it and couldn't run without it. Extensions and utilities from other frameworks or even the net/http package can be easily implemented into Yarf by just wraping them up into a Resource, just as you would do on any other framework by wrapping functions.

Context handling also shows some weird designs across frameworks. Some of them rely on reflection to receive any kind of handlers and context types. Others make you receive some extra parameter in the handler function that actually brokes the net/http compatibility, and you have to carry that context parameter through all middleware/handler-wrapper functions just to make it available. In Yarf, the Context is automatically sent as a parameter to all Resource methods by the framework.

For all the reasons above, among some others, there is a new framework in town.




View Source
const Version = "0.8.5"

    Version string


    This section is empty.


    This section is empty.


    type Cache

    type Cache struct {
    	// Sync Mutex
    	// contains filtered or unexported fields

      Cache is the service handler for route caching

      func NewCache

      func NewCache() *Cache

        NewCache creates and initializes a new Cache service object.

        func (*Cache) Get

        func (c *Cache) Get(k string) (rc RouteCache, ok bool)

          Get retrieves a routeCache object by key name.

          func (*Cache) Set

          func (c *Cache) Set(k string, r RouteCache)

            Set stores a routeCache object under a key name.

            type Context

            type Context struct {
            	// The *http.Request object as received by the HandleFunc.
            	Request *http.Request
            	// The http.ResponseWriter object as received by the HandleFunc.
            	Response http.ResponseWriter
            	// Parameters received through URL route
            	Params Params
            	// Free storage to be used freely by apps to their convenience.
            	Data ContextData
            	// contains filtered or unexported fields

              Context is the data/status storage of every YARF request. Every request will instantiate a new Context object and fill in with all the request data. Each request Context will be shared along the entire request life to ensure accesibility of its data at all levels.

              func NewContext

              func NewContext(r *http.Request, rw http.ResponseWriter) *Context

                NewContext creates a new *Context object with default values and returns it.

                func (*Context) FormValue

                func (c *Context) FormValue(name string) string

                  FormValue is a wrapper for c.Request.Form.Get() and it calls c.Request.ParseForm().

                  func (*Context) GetClientIP

                  func (c *Context) GetClientIP() (ip string)

                    GetClientIP retrieves the client IP address from the request information. It detects common proxy headers to return the actual client's IP and not the proxy's.

                    func (*Context) Param

                    func (c *Context) Param(name string) string

                      Param is a wrapper for c.Params.Get()

                      func (*Context) QueryValue

                      func (c *Context) QueryValue(name string) string

                        QueryValue is a wrapper for c.Request.URL.Query().Get().

                        func (*Context) Redirect

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

                          Redirect sends the corresponding HTTP redirect response with the provided URL and status code. It's just a wrapper for net/http.Redirect()

                          func (*Context) Render

                          func (c *Context) Render(content string)

                            Render writes a string to the http.ResponseWriter. This is the default renderer that just sends the string to the client. Check other Render[Type] functions for different types.

                            func (*Context) RenderGzip

                            func (c *Context) RenderGzip(content []byte) error

                              RenderGzip takes a []byte content and if the client accepts compressed responses, writes the compressed version of the content to the response. Otherwise it just writes the plain []byte to it.

                              func (*Context) RenderGzipJSON

                              func (c *Context) RenderGzipJSON(data interface{})

                                RenderGzipJSON takes a interface{} object and writes the JSON verion through RenderGzip.

                                func (*Context) RenderGzipXML

                                func (c *Context) RenderGzipXML(data interface{})

                                  RenderGzipXML takes a interface{} object and writes the XML verion through RenderGzip.

                                  func (*Context) RenderJSON

                                  func (c *Context) RenderJSON(data interface{})

                                    RenderJSON takes a interface{} object and writes the JSON encoded string of it.

                                    func (*Context) RenderJSONIndent

                                    func (c *Context) RenderJSONIndent(data interface{})

                                      RenderJSONIndent is the indented (beauty) of RenderJSON

                                      func (*Context) RenderXML

                                      func (c *Context) RenderXML(data interface{})

                                        RenderXML takes a interface{} object and writes the XML encoded string of it.

                                        func (*Context) RenderXMLIndent

                                        func (c *Context) RenderXMLIndent(data interface{})

                                          RenderXMLIndent is the indented (beauty) of RenderXML

                                          func (*Context) Status

                                          func (c *Context) Status(code int)

                                            Status sets the HTTP status code to be returned on the response.

                                            type ContextData

                                            type ContextData interface {
                                            	// Get retrieves a data item by it's key name.
                                            	Get(key string) (interface{}, error)
                                            	// Set saves a data item under a key name.
                                            	Set(key string, data interface{}) error
                                            	// Del removes the data item and key name for a given key.
                                            	Del(key string) error

                                              ContextData interface represents a common get/set/del set of methods to handle data storage. Is designed to be used as the Data property of the Context obejct. The Data property is a free storage unit that apps using the framework can implement to their convenience to share context data during a request life. All methods returns an error status that different implementations can design to fulfill their needs.

                                              type CustomError

                                              type CustomError struct {
                                              	HTTPCode  int    // HTTP status code to be used as this error response.
                                              	ErrorCode int    // Internal YARF error code for further reference.
                                              	ErrorMsg  string // YARF error message.
                                              	ErrorBody string // Error content to be rendered to the client response.

                                                CustomError is the standard error response format used through the framework. Implements Error and YError interfaces

                                                func (*CustomError) Body

                                                func (e *CustomError) Body() string

                                                  Body returns the error's content body, if needed, to be returned in the HTTP response.

                                                  func (*CustomError) Code

                                                  func (e *CustomError) Code() int

                                                    Code returns the error's HTTP code to be used in the response.

                                                    func (*CustomError) Error

                                                    func (e *CustomError) Error() string

                                                      Implements the error interface returning the ErrorMsg value of each error.

                                                      func (*CustomError) ID

                                                      func (e *CustomError) ID() int

                                                        ID returns the error's ID for further reference.

                                                        func (*CustomError) Msg

                                                        func (e *CustomError) Msg() string

                                                          Msg returns the error's message, used to implement the Error interface.

                                                          type GroupRoute

                                                          type GroupRoute struct {
                                                          	// contains filtered or unexported fields

                                                            GroupRoute stores routes grouped under a single url prefix.

                                                            func RouteGroup

                                                            func RouteGroup(url string) *GroupRoute

                                                              RouteGroup creates a new GroupRoute object and initializes it with the provided url prefix. The object implements Router interface to being able to handle groups as routes. Groups can be nested into each other, so it's possible to add a GroupRoute as a route inside another GroupRoute. Includes methods to work with middleware.

                                                              func (*GroupRoute) Add

                                                              func (g *GroupRoute) Add(url string, h ResourceHandler)

                                                                Add inserts a new resource with it's associated route into the group object.

                                                                func (*GroupRoute) AddGroup

                                                                func (g *GroupRoute) AddGroup(r *GroupRoute)

                                                                  AddGroup inserts a GroupRoute into the routes list of the group object. This makes possible to nest groups.

                                                                  func (*GroupRoute) Dispatch

                                                                  func (g *GroupRoute) Dispatch(c *Context) (err error)

                                                                    Dispatch loops through all routes inside the group and dispatch the one that matches the request. Outside the box, works exactly the same as route.Dispatch().

                                                                    func (*GroupRoute) Insert

                                                                    func (g *GroupRoute) Insert(m MiddlewareHandler)

                                                                      Insert adds a MiddlewareHandler into the middleware list of the group object.

                                                                      func (*GroupRoute) Match

                                                                      func (g *GroupRoute) Match(url string, c *Context) bool

                                                                        Match loops through all routes inside the group and find for one that matches the request. After a match is found, the route matching is stored into Context.groupDispatch to being able to dispatch it directly after a match without looping again. Outside the box, works exactly the same as route.Match()

                                                                        type GroupRouter

                                                                        type GroupRouter interface {
                                                                        	Add(string, ResourceHandler)

                                                                          GroupRouter interface adds methods to work with children routers

                                                                          type MethodNotImplementedError

                                                                          type MethodNotImplementedError struct {

                                                                            MethodNotImplementedError is used to communicate that a specific HTTP method isn't implemented by a resource.

                                                                            func ErrorMethodNotImplemented

                                                                            func ErrorMethodNotImplemented() *MethodNotImplementedError

                                                                              ErrorMethodNotImplemented creates MethodNotImplementedError

                                                                              type Middleware

                                                                              type Middleware struct{}

                                                                                Middleware struct is the default implementation of a Middleware and does nothing. Users can either implement both methods or composite this struct into their own. Both methods needs to be present to satisfy the MiddlewareHandler interface.

                                                                                func (*Middleware) End

                                                                                func (m *Middleware) End(c *Context) error

                                                                                  End will be executed ALWAYS after every request, even if there were errors present.

                                                                                  func (*Middleware) PostDispatch

                                                                                  func (m *Middleware) PostDispatch(c *Context) error

                                                                                    PostDispatch includes code to be executed after every Resource request.

                                                                                    func (*Middleware) PreDispatch

                                                                                    func (m *Middleware) PreDispatch(c *Context) error

                                                                                      PreDispatch includes code to be executed before every Resource request.

                                                                                      type MiddlewareHandler

                                                                                      type MiddlewareHandler interface {
                                                                                      	PreDispatch(*Context) error
                                                                                      	PostDispatch(*Context) error
                                                                                      	End(*Context) error

                                                                                        MiddlewareHandler interface provides the methods for request filters that needs to run before, or after, every request Resource is executed.

                                                                                        type NotFoundError

                                                                                        type NotFoundError struct {

                                                                                          NotFoundError is the HTTP 404 error equivalent.

                                                                                          func ErrorNotFound

                                                                                          func ErrorNotFound() *NotFoundError

                                                                                            ErrorNotFound creates NotFoundError

                                                                                            type Params

                                                                                            type Params map[string]string

                                                                                              Params wraps a map[string]string and adds Get/Set/Del methods to work with it. Inspired on url.Values but simpler as it doesn't handles a map[string][]string

                                                                                              func (Params) Del

                                                                                              func (p Params) Del(key string)

                                                                                                Del deletes the values associated with key.

                                                                                                func (Params) Get

                                                                                                func (p Params) Get(key string) string

                                                                                                  Get gets the first value associated with the given key. If there are no values associated with the key, Get returns the empty string.

                                                                                                  func (Params) Set

                                                                                                  func (p Params) Set(key, value string)

                                                                                                    Set sets the key to value. It replaces any existing values.

                                                                                                    type Resource

                                                                                                    type Resource struct{}

                                                                                                      The Resource type is the representation of each REST resource of the application. It implements the ResourceHandler interface and allows the developer to extend the methods needed. All resources being used by a YARF application have to composite this Resource struct.

                                                                                                      func (*Resource) Connect

                                                                                                      func (r *Resource) Connect(c *Context) error

                                                                                                        Connect is the default HTTP CONNECT implementation. It returns a NotImplementedError

                                                                                                        func (*Resource) Delete

                                                                                                        func (r *Resource) Delete(c *Context) error

                                                                                                          Delete is the default HTTP DELETE implementation. It returns a NotImplementedError

                                                                                                          func (*Resource) Get

                                                                                                          func (r *Resource) Get(c *Context) error

                                                                                                            Get is the default HTTP GET implementation. It returns a NotImplementedError

                                                                                                            func (*Resource) Head

                                                                                                            func (r *Resource) Head(c *Context) error

                                                                                                              Head is the default HTTP HEAD implementation. It returns a NotImplementedError

                                                                                                              func (*Resource) Options

                                                                                                              func (r *Resource) Options(c *Context) error

                                                                                                                Options is the default HTTP OPTIONS implementation. It returns a NotImplementedError

                                                                                                                func (*Resource) Patch

                                                                                                                func (r *Resource) Patch(c *Context) error

                                                                                                                  Patch is the default HTTP PATCH implementation. It returns a NotImplementedError

                                                                                                                  func (*Resource) Post

                                                                                                                  func (r *Resource) Post(c *Context) error

                                                                                                                    Post is the default HTTP POST implementation. It returns a NotImplementedError

                                                                                                                    func (*Resource) Put

                                                                                                                    func (r *Resource) Put(c *Context) error

                                                                                                                      Put is the default HTTP PUT implementation. It returns a NotImplementedError

                                                                                                                      func (*Resource) Trace

                                                                                                                      func (r *Resource) Trace(c *Context) error

                                                                                                                        Trace is the default HTTP TRACE implementation. It returns a NotImplementedError

                                                                                                                        type ResourceHandler

                                                                                                                        type ResourceHandler interface {
                                                                                                                        	// HTTP methods
                                                                                                                        	Get(*Context) error
                                                                                                                        	Post(*Context) error
                                                                                                                        	Put(*Context) error
                                                                                                                        	Patch(*Context) error
                                                                                                                        	Delete(*Context) error
                                                                                                                        	Options(*Context) error
                                                                                                                        	Head(*Context) error
                                                                                                                        	Trace(*Context) error
                                                                                                                        	Connect(*Context) error

                                                                                                                          The ResourceHandler interface defines how Resources through the application have to be defined. Ideally, the developer will composite the Resource struct into their own resources, but it's possible to implement each one by their own.

                                                                                                                          type RouteCache

                                                                                                                          type RouteCache struct {
                                                                                                                          	// contains filtered or unexported fields

                                                                                                                            RouteCache stores previously matched and parsed routes

                                                                                                                            type Router

                                                                                                                            type Router interface {
                                                                                                                            	Match(string, *Context) bool
                                                                                                                            	Dispatch(*Context) error

                                                                                                                              Router interface provides the methods used to handle route and GroupRoute objects.

                                                                                                                              func Route

                                                                                                                              func Route(url string, h ResourceHandler) Router

                                                                                                                                Route returns a new route object initialized with the provided data. Params:

                                                                                                                                - url string 		// The route path to handle
                                                                                                                                - h	ResourceHandler	// The ResourceHandler object that will process the requests to the url.

                                                                                                                                type UnexpectedError

                                                                                                                                type UnexpectedError struct {

                                                                                                                                  UnexpectedError is used when the origin of the error can't be discovered

                                                                                                                                  func ErrorUnexpected

                                                                                                                                  func ErrorUnexpected() *UnexpectedError

                                                                                                                                    ErrorUnexpected creates UnexpectedError

                                                                                                                                    type YError

                                                                                                                                    type YError interface {
                                                                                                                                    	Code() int    // HTTP response code for this error
                                                                                                                                    	ID() int      // Error code ID.
                                                                                                                                    	Msg() string  // Error description
                                                                                                                                    	Body() string // Error body content to be returned to the client if needed.

                                                                                                                                      YError is the interface used to handle error responses inside the framework.

                                                                                                                                      type Yarf

                                                                                                                                      type Yarf struct {
                                                                                                                                      	// UseCache indicates if the route cache should be used.
                                                                                                                                      	UseCache bool
                                                                                                                                      	// Debug enables/disables the debug mode.
                                                                                                                                      	// On debug mode, extra error information is sent to the client.
                                                                                                                                      	Debug bool
                                                                                                                                      	// PanicHandler can store a func() that will be defered by each request to be able to recover().
                                                                                                                                      	// If you need to log, send information or do anything about a panic, this is your place.
                                                                                                                                      	PanicHandler func()
                                                                                                                                      	// Logger object will be used if present
                                                                                                                                      	Logger *log.Logger
                                                                                                                                      	// Follow defines a standard http.Handler implementation to follow if no route matches.
                                                                                                                                      	Follow http.Handler
                                                                                                                                      	// NotFound defines a function interface to execute when a NotFound (404) error is thrown.
                                                                                                                                      	NotFound func(c *Context)
                                                                                                                                      	// contains filtered or unexported fields

                                                                                                                                        Yarf is the main entry point for the framework and it centralizes most of the functionality. All configuration actions are handled by this object.

                                                                                                                                        func New

                                                                                                                                        func New() *Yarf

                                                                                                                                          New creates a new yarf and returns a pointer to it. Performs needed initializations

                                                                                                                                          func (*Yarf) ServeHTTP

                                                                                                                                          func (y *Yarf) ServeHTTP(res http.ResponseWriter, req *http.Request)

                                                                                                                                            ServeHTTP Implements http.Handler interface into yarf. Initializes a Context object and handles middleware and route actions. If an error is returned by any of the actions, the flow is stopped and a response is sent. If no route matches, tries to forward the request to the Yarf.Follow (http.Handler type) property if set. Otherwise it returns a 404 response.

                                                                                                                                            func (*Yarf) Start

                                                                                                                                            func (y *Yarf) Start(address string)

                                                                                                                                              Start initiates a new http yarf server and start listening. It's a shortcut for http.ListenAndServe(address, y)

                                                                                                                                              func (*Yarf) StartTLS

                                                                                                                                              func (y *Yarf) StartTLS(address, cert, key string)

                                                                                                                                                StartTLS initiates a new http yarf server and starts listening to HTTPS requests. It is a shortcut for http.ListenAndServeTLS(address, cert, key, yarf)


                                                                                                                                                Path Synopsis
                                                                                                                                                The complete example implements all possible features from YARF.
                                                                                                                                                The complete example implements all possible features from YARF.
                                                                                                                                                static example package demonstrates how to easily implement a yarf handler that serves static files using the net/http package.
                                                                                                                                                static example package demonstrates how to easily implement a yarf handler that serves static files using the net/http package.