README

Fireball

MIT License Go Report Card Go Doc

Overview

Fireball is a package for Go web applications. The primary goal of this package is to make routing, response writing, and error handling as easy as possible for developers, so they can focus more on their application logic, and less on repeated patterns.

Installation

To install this package, run:

go get github.com/zpatrick/fireball

Getting Started

The following snipped shows a simple "Hello, World" application using Fireball:

package main

import (
  "github.com/zpatrick/fireball"
  "net/http"
)

func index(c *fireball.Context) (fireball.Response, error) {
  return fireball.NewResponse(200, []byte("Hello, World!"), nil), nil
}

func main() {
  indexRoute := &fireball.Route{
    Path: "/",
    Handlers: fireball.Handlers{
      "GET": index,
    },
  }

  routes := []*fireball.Route{indexRoute}
  app := fireball.NewApp(routes)
  http.ListenAndServe(":8000", app)
}

This will run a new webserver at localhost:8000

Handlers

Handlers perform the business logic associated with requests. Handlers take a Context object and returns either a Response or an error.

HTTP Response

The HTTP Response is a simple object that implements the Response interface. When the Write call is executed, the specified Body, Status, and Headers will be written to the http.ResponseWriter.

Examples:

func Index(c *fireball.Context) (fireball.Response, error) {
    return fireball.NewResponse(200, []byte("Hello, World"), nil), nil
}
func Index(c *fireball.Context) (fireball.Response, error) {
    html := []byte("<h1>Hello, World</h1>")
    return fireball.NewResponse(200, html, fireball.HTMLHeaders), nil
}
HTTP Error

If a Handler returns a non-nil error, the Fireball Application will call its ErrorHandler function. By default (if your Application object uses the DefaultErrorHandler), the Application will check if the error implements the Response interface. If so, the the error's Write function will be called. Otherwise, a 500 with the content of err.Error() will be written.

The HTTPError is a simple object that implements both the Error and Response interfaces. When the Write is executed, the specified status, error, and headers will be written to the http.ResponseWriter.

Examples:

func Index(c *fireball.Context) (fireball.Response, error) {
    return nil, fmt.Errorf("an error occurred")
}
func Index(c *fireball.Context) (fireball.Response, error) {
    if err := do(); err != nil {
        return nil, fireball.NewError(500, err, nil)
    }
    
    ...
}

Routing

Basic Router

By default, Fireball uses the BasicRouter object to match requests to Route objects. The Route's Path field determines which URL patterns should be dispached to your Route. The Route's Handlers field maps different HTTP methods to different Handlers.

You can use :variable notation in the Path to match any string that doesn't contain a "/" character. The variables defined in the Route's Path field can be accessed using the Context object.

Example:

route := &Fireball.Route{
  Path: "/users/:userID/orders/:orderID",
  Methods: fireball.Handlers{
    "GET": printUserOrder,
  },
}

func printUserOrder(c *fireball.Context) (fireball.Response, error) {
    userID := c.PathVariables["userID"]
    orderID := c.PathVariables["orderID"]
    message := fmt.Sprintf("User %s ordered item %s", userID, orderID)
    
    return fireball.NewResponse(200, []byte(message), nil)
}
Static Routing

The built-in FileServer can be used to serve static content. The follow snippet would serve files from the static directory:

  app := fireball.NewApp(...)
  http.Handle("/", app)

  fs := http.FileServer(http.Dir("static"))
  http.Handle("/static/", http.StripPrefix("/static", fs))
  
  http.ListenAndServe(":8000", nil)

If the application workspace contained:

app/
    main.go
    static/
        hello_world.txt

A request to /static/hello_world.txt would serve the desired file.

HTML Templates

By default, Fireball uses the GlobParser to render HTML templates. This object recursively searches a given directory for template files matching the given glob pattern. The default root directory is "views", and the default glob pattern is "*.html" The name of the templates are path/from/root/directory + filename.

For example, if the filesystem contained:

views/
    index.html
    partials/
        login.html

The templates names generated would be "index.html", and "partials/login.html". The Context contains a helper function, HTML, which renders templates as HTML.

Example:

func Index(c *fireball.Context) (fireball.Response, error) {
    data := "Hello, World!"
    return c.HTML(200, "index.html", data)
}

Decorators

Decorators can be used to wrap additional logic around Handlers. Fireball has some built-in decorators:

In addition to Decorators, the Before and After functions on the Application object can be used to perform logic when the request is received and after the response has been sent.

Examples & Extras

License

This work is published under the MIT license.

Please see the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	HTMLHeaders = map[string]string{"Content-Type": "text/html"}
	JSONHeaders = map[string]string{"Content-Type": "application/json"}
	TextHeaders = map[string]string{"Content-Type": "text/plain"}
	CORSHeaders = map[string]string{
		"Access-Control-Allow-Origin":      "*",
		"Access-Control-Allow-Credentials": "true",
		"Access-Control-Allow-Headers":     "Authorization, Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers",
		"Access-Control-Allow-Methods":     "GET, POST, PUT, PATCH, DELETE, COPY, HEAD, OPTIONS, LINK, UNLINK, CONNECT, TRACE, PURGE",
	}
)

Functions

func DefaultErrorHandler

func DefaultErrorHandler(w http.ResponseWriter, r *http.Request, err error)

    DefaultErrorHandler is the default ErrorHandler used by an App If the error implements the Response interface, it will call its Write function Otherwise, a 500 with the error message is returned

    func RecordJSONResponse

    func RecordJSONResponse(t *testing.T, resp Response, v interface{}) *httptest.ResponseRecorder

    Types

    type App

    type App struct {
    	// The After function is called after each request has completed
    	After func(http.ResponseWriter, *http.Request)
    	// The Before function is called before each request is routed
    	Before func(http.ResponseWriter, *http.Request)
    	// The ErrorHandler is called whenever a Handler returns a non-nil error
    	ErrorHandler func(http.ResponseWriter, *http.Request, error)
    	// The NotFoundHandler is called whenever the Router returns a nil RouteMatch
    	NotFoundHandler func(http.ResponseWriter, *http.Request)
    	// The template parser is passed into the Context
    	Parser TemplateParser
    	// The router is used to match a request to a Handler whenever a request is made
    	Router Router
    }

      App is the main structure of fireball applications. It can be invoked as an http.Handler

      func NewApp

      func NewApp(routes []*Route) *App

        NewApp returns a new App object with all of the default fields

        func (*App) ServeHTTP

        func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request)

        type BasicRouter

        type BasicRouter struct {
        	Routes []*Route
        	// contains filtered or unexported fields
        }

          BasicRouter attempts to match requests based on its Routes. This router supports variables in the URL by using ":variable" notation in URL sections. For example, the following are all valid Paths:

          "/home"
          "/movies/:id"
          "/users/:userID/purchases/:purchaseID"
          

          Matched Path Variables can be retrieved in Handlers by the Context:

          func Handler(c *Context) (Response, error) {
              id := c.PathVariables["id"]
              ...
          }
          

          func NewBasicRouter

          func NewBasicRouter(routes []*Route) *BasicRouter

            NewBasicRouter returns a new BasicRouter with the specified Routes

            func (*BasicRouter) Match

            func (r *BasicRouter) Match(req *http.Request) (*RouteMatch, error)

              Match attempts to match the *http.Request to a Route. Successful matches are cached for improved performance.

              type Context

              type Context struct {
              	// PathVariables are the URL-related variables returned by the Router
              	PathVariables map[string]string
              	// Meta can be used to pass information along Decorators
              	Meta map[string]interface{}
              	// Parser is used to render html templates
              	Parser TemplateParser
              	// Request is the originating *http.Request
              	Request *http.Request
              }

                Context is passed into Handlers It contains fields and helper functions related to the request

                func (*Context) HTML

                func (c *Context) HTML(status int, templateName string, data interface{}) (*HTTPResponse, error)

                  Context.HTML calls HTML with the Context's template parser

                  type Decorator

                  type Decorator func(Handler) Handler

                    A Decorator wraps logic around a Handler

                    func BasicAuthDecorator

                    func BasicAuthDecorator(username, password string) Decorator

                      BasicAuthDecorator will add basic authentication using the specified username and password

                      func HeaderResponseDecorator

                      func HeaderResponseDecorator(headers map[string]string) Decorator

                        HeaderResponseDecorator will add the specified headers to each response

                        func LogDecorator

                        func LogDecorator() Decorator

                          LogDecorator will print the method and url of each request

                          type GlobParser

                          type GlobParser struct {
                          	Root string
                          	Glob string
                          	// contains filtered or unexported fields
                          }

                            GlobParser generates a template by recusively searching the specified root directory and parses templates that match the specified glob pattern

                            func NewGlobParser

                            func NewGlobParser(root, glob string) *GlobParser

                              NewGlobParser returns a GlobParser with the specified root and glob pattern

                              func (*GlobParser) Parse

                              func (p *GlobParser) Parse() (*template.Template, error)

                                Parse recursively searches the root directory and parses templates that match the specified glob pattern. Template names are generated by path/from/root + filename.

                                For example, if GlobParser.Root == "views", the following template names would be generated:

                                Files:
                                  views/
                                    index.html
                                    partials/
                                      login.html
                                
                                Template Names:
                                  "index.html"
                                  "partials/login.html"
                                

                                type HTTPError

                                type HTTPError struct {
                                	*HTTPResponse
                                	Err error
                                }

                                  HTTPError implements the Response and Error interfaces

                                  func NewError

                                  func NewError(status int, err error, headers map[string]string) *HTTPError

                                    NewError returns a new HTTPError

                                    func NewJSONError

                                    func NewJSONError(status int, err error) (*HTTPError, error)

                                      NewJSONError returns a new HTTPError in JSON format

                                      func (*HTTPError) Error

                                      func (e *HTTPError) Error() string

                                        Error calls the internal Err.Error function

                                        type HTTPResponse

                                        type HTTPResponse struct {
                                        	Status  int
                                        	Body    []byte
                                        	Headers map[string]string
                                        }

                                          HTTPResponse objects write the specified status, headers, and body to a http.ResponseWriter

                                          func HTML

                                          func HTML(parser TemplateParser, status int, templateName string, data interface{}) (*HTTPResponse, error)

                                            HTML is a helper function that returns a response generated from the given templateName and data

                                            func NewJSONResponse

                                            func NewJSONResponse(status int, data interface{}) (*HTTPResponse, error)

                                              NewJSONResponse returns a new HTTPResponse in JSON format

                                              func NewResponse

                                              func NewResponse(status int, body []byte, headers map[string]string) *HTTPResponse

                                                NewResponse returns a new HTTPResponse with the specified status, body, and headers

                                                func (*HTTPResponse) Write

                                                func (h *HTTPResponse) Write(w http.ResponseWriter, r *http.Request)

                                                  Write will write the specified status, headers, and body to the http.ResponseWriter

                                                  type Handler

                                                  type Handler func(c *Context) (Response, error)

                                                    Handler performs the business logic on a request

                                                    type Handlers

                                                    type Handlers map[string]Handler

                                                      Handlers maps a http method to a Handler

                                                      type Response

                                                      type Response interface {
                                                      	Write(http.ResponseWriter, *http.Request)
                                                      }

                                                        Response is an object that writes to an http.ResponseWriter A Response object implements the http.Handler interface

                                                        func Redirect

                                                        func Redirect(status int, url string) Response

                                                          Redirect wraps http.Redirect in a ResponseFunc

                                                          type ResponseFunc

                                                          type ResponseFunc func(http.ResponseWriter, *http.Request)

                                                            ResponseFunc is a function which implements the Response interface

                                                            func (ResponseFunc) Write

                                                            func (rf ResponseFunc) Write(w http.ResponseWriter, r *http.Request)

                                                            type Route

                                                            type Route struct {
                                                            	// Path is used to determine if a request's URL matches this Route
                                                            	Path string
                                                            	// Handlers map common HTTP methods to different Handlers
                                                            	Handlers map[string]Handler
                                                            }

                                                              Routes are used to map a request to a RouteMatch

                                                              func Decorate

                                                              func Decorate(routes []*Route, decorators ...Decorator) []*Route

                                                                Decorate is a helper function that decorates each Handler in each Route with the given Decorators

                                                                func EnableCORS

                                                                func EnableCORS(routes []*Route) []*Route

                                                                  EnableCORS decorates each route by adding CORS headers to each response An OPTIONS Handler is added to each route if one doesn't already exist

                                                                  type RouteMatch

                                                                  type RouteMatch struct {
                                                                  	Handler       Handler
                                                                  	PathVariables map[string]string
                                                                  }

                                                                    RouteMatch objects are returned by the router when a request is successfully matched

                                                                    type Router

                                                                    type Router interface {
                                                                    	Match(*http.Request) (*RouteMatch, error)
                                                                    }

                                                                      Router is an interface that matches an *http.Request to a RouteMatch. If no matches are found, a nil RouteMatch should be returned.

                                                                      type RouterFunc

                                                                      type RouterFunc func(*http.Request) (*RouteMatch, error)

                                                                        RouterFunc is a function which implements the Router interface

                                                                        func (RouterFunc) Match

                                                                        func (rf RouterFunc) Match(r *http.Request) (*RouteMatch, error)

                                                                        type TemplateParser

                                                                        type TemplateParser interface {
                                                                        	Parse() (*template.Template, error)
                                                                        }

                                                                          TemplateParser is an interface object that is used to parse HTML templates

                                                                          type TemplateParserFunc

                                                                          type TemplateParserFunc func() (*template.Template, error)

                                                                            TemplateParserFunc is a function which implements the TemplateParser interface

                                                                            func (TemplateParserFunc) Parse

                                                                            func (tpf TemplateParserFunc) Parse() (*template.Template, error)