fireball

package module
v0.0.0-...-f42d3a4 Latest Latest
Warning

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

Go to latest
Published: Oct 3, 2018 License: MIT Imports: 12 Imported by: 14

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)

Jump to

Keyboard shortcuts

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