flash

package module
v0.0.0-...-2b6e198 Latest Latest
Warning

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

Go to latest
Published: Jun 12, 2015 License: MIT Imports: 16 Imported by: 0

README

flash

HTTP routing package that helps to create restfull json api for Go applications.

what it does:

  • dispatching actions to controllers
  • rendering JSON response
  • extracting JSON request data by key
  • handling file uploads
  • sending gzipped JSON responses when applicable
  • sending gzipped versions of static files if any

Routing:

r := flash.NewRouter()

// route to function(*Ctx)
r.Route("/pages/:id", ShowPage)

// auto generates controller routes
r.Resource("/pages", &PagesController{})

// standard http handler
r.HandleFunc("/", IndexHandler)

URL Parameters:

// prefixed with ':' are strict params. all parts should be present in request
// strict params can't be used after optional or global params
// Request: '/pages/1/act' Returns: [id:1, action:act]
// Request: '/pages/1' Returns: not found
"/pages/:id/:action"

// prefixed with '&' are optional params. any or non can be present in request
// Request: '/pages/1/act' Returns: [id:1, action:act]
// Request: '/pages/1' Returns: [id:1]
// Request: '/pages' Returns: []
"/pages/&id/&action"

// prefixed with '@' are global params. global param returns the rest of request
// global param can only be used as last param
// Request: '/files/path_to/file.go' Returns: [name:"path_to/file.go"]
"/files/@name"

standard REST usage example:

package main

import (
	"net/http"

	"github.com/vtg/flash"
)

var pages map[int64]*Page

func main() {
	pages = make(map[int64]*Page)
	pages[1] = &Page{Id: 1, Name: "Page 1"}
	pages[2] = &Page{Id: 2, Name: "Page 2"}

	r := flash.NewRouter()
	a := r.PathPrefix("/api/v1")

	a.Resource("/pages", &Pages{}, auth)
	r.PathPrefix("/images/").FileServer("./public/")
	r.HandleFunc("/", indexHandler)
	http.ListenAndServe(":8080", r)
}

// simple authentication implementation
func auth(c *flash.Ctx) bool {
	key := c.QueryParam("key")
	if key == "correct-password" {
		return true
	} else {
		c.RenderJSONError(http.StatusUnauthorized, "unauthorized")
	}
	return false
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello"))
}

type Page struct {
	Id      int64  `json:"id"`
	Name    string `json:"name"`
	Content string `json:"content"`
	Visible bool   `json:"visible"`
}

func findPage(id int64) *Page {
	p := pages[id]
	return p
}
func insertPage(p Page) *Page {
	id := int64(len(pages) + 1)
	p.Id = id
	pages[id] = &p
	return pages[id]
}

// Pages used as controller
type Pages struct {
	flash.Ctx
}

// Index processed on GET /pages
func (p *Pages) Index() {
	var res []*Page

	for _, v := range pages {
		res = append(res, v)
	}

	p.RenderJSON(200, flash.JSON{"pages": res})
}

// Show processed on GET /pages/1
func (p *Pages) Show() {
	page := findPage(p.ID64())

	if page == nil {
		p.RenderJSONError(404, "record not found")
		return
	}

	p.RenderJSON(200, flash.JSON{"page": page})
}

// Create processed on POST /pages
// with input data provided {"page":{"name":"New Page","content":"some content"}}
func (p *Pages) Create() {
	m := Page{}
	if m.Name == "" {
		// see Request.LoadJSONRequest for more info
		p.LoadJSONRequest("page", &m)
		p.RenderJSONError(422, "name required")
	} else {
		insertPage(m)
		p.RenderJSON(200, flash.JSON{"page": m})
	}
}

// Update processed on PUT /pages/1
// with input data provided {"page":{"name":"Page 1","content":"updated content"}}
func (p *Pages) Update() {
	page := findPage(p.ID64())

	if page == nil {
		p.RenderJSONError(404, "record not found")
		return
	}

	m := Page{}
	p.LoadJSONRequest("page", &m)
	page.Content = m.Content
	p.RenderJSON(200, flash.JSON{"page": page})
}

// Destroy processed on DELETE /pages/1
func (p *Pages) Destroy() {
	page := findPage(p.ID64())

	if page == nil {
		p.RenderJSONError(404, "record not found")
		return
	}

	delete(pages, page.Id)
	p.RenderJSON(203, flash.JSON{})
}

// POSTActivate custom non crud action activates/deactivated page. processed on POST /pages/1/activate
func (p *Pages) POSTActivate() {
	page := findPage(p.ID64())
	if page == nil {
		p.RenderJSONError(404, "record not found")
		return
	}

	page.Visible = !page.Visible
	p.RenderJSON(200, flash.JSON{"page": page})
}

Its possible to serve custom actions. To add custom action to controller prefix action name with HTTP method:

 // POST /pages/clean or POST /pages/1/clean
 func (p *Pages) POSTClean {
   // do some work here
 }
 // DELETE /pages/clean or DELETE /pages/1/clean
 func (p *Pages) DELETEClean {
   // do some work here
 }
 // GET /pages/stat or GET /pages/1/stat
 func (p *Pages) GETStat {
   // do some work here
 }
 ...

#####Author

VTG - http://github.com/vtg

License

Released under the MIT License.

GoDoc

Documentation

Overview

HTTP routing package that helps to create restfull json api for Go applications.

what it does:

  • dispatching actions to controllers
  • rendering JSON response
  • extracting JSON request data by key
  • handling file uploads
  • sending gzipped JSON responses when applicable
  • sending gzipped versions of static files if any

standard REST usage example:

package main

import (
  "net/http"

  "github.com/vtg/flash"
)

var pages map[int64]*Page

func main() {
  pages = make(map[int64]*Page)
  pages[1] = &Page{Id: 1, Name: "Page 1"}
  pages[2] = &Page{Id: 2, Name: "Page 2"}

  r := flash.NewRouter()
  a := r.PathPrefix("/api/v1")

  // see Route.Route for more info
  a.Resource("/pages", &Pages{}, auth)

  // see Route.FileServer for more info
  r.PathPrefix("/images/").FileServer("./public/")
  r.HandleFunc("/", indexHandler)
  http.ListenAndServe(":8080", r)
}

// simple quthentication implementation
func auth(c *flash.Ctx) bool {
  key := c.QueryParam("key")
  if key == "correct-password" {
    return true
  } else {
    c.RenderJSONError(http.StatusUnauthorized, "unauthorized")
  }
  return false
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
  w.Write([]byte("hello"))
}

type Page struct {
  Id      int64  `json:"id"`
  Name    string `json:"name"`
  Content string `json:"content"`
  Visible bool   `json:"visible"`
}

func findPage(id int64) *Page {
  p := pages[id]
  return p
}
func insertPage(p Page) *Page {
  id := int64(len(pages) + 1)
  p.Id = id
  pages[id] = &p
  return pages[id]
}

// Pages used as controller
type Pages struct {
  flash.Ctx
}

// Index processed on GET /pages
func (p *Pages) Index() {
  var res []*Page

  for _, v := range pages {
    res = append(res, v)
  }

  p.RenderJSON(200, flash.JSON{"pages": res})
}

// Show processed on GET /pages/1
func (p *Pages) Show() {
  page := findPage(p.ID64())

  if page == nil {
    p.RenderJSONError(404, "record not found")
    return
  }

  p.RenderJSON(200, flash.JSON{"page": page})
}

// Create processed on POST /pages
// with input data provided {"page":{"name":"New Page","content":"some content"}}
func (p *Pages) Create() {
  m := Page{}
  if m.Name == "" {
    // see Request.LoadJSONRequest for more info
    p.LoadJSONRequest("page", &m)
    p.RenderJSONError(422, "name required")
  } else {
    insertPage(m)
    p.RenderJSON(200, flash.JSON{"page": m})
  }
}

// Update processed on PUT /pages/1
// with input data provided {"page":{"name":"Page 1","content":"updated content"}}
func (p *Pages) Update() {
  page := findPage(p.ID64())

  if page == nil {
    p.RenderJSONError(404, "record not found")
    return
  }

  m := Page{}
  p.LoadJSONRequest("page", &m)
  page.Content = m.Content
  p.RenderJSON(200, flash.JSON{"page": page})
}

// Destroy processed on DELETE /pages/1
func (p *Pages) Destroy() {
  page := findPage(p.ID64())

  if page == nil {
    p.RenderJSONError(404, "record not found")
    return
  }

  delete(pages, page.Id)
  p.RenderJSON(203, flash.JSON{})
}

// POSTActivate custom non crud action activates/deactivated page. processed on POST /pages/1/activate
func (p *Pages) POSTActivate() {
  page := findPage(p.ID64())
  if page == nil {
    p.RenderJSONError(404, "record not found")
    return
  }

  page.Visible = !page.Visible
  p.RenderJSON(200, flash.JSON{"page": page})
}

Its possible to serve custom actions. To add custom action to controller prefix action name with HTTP method:

// POST /pages/clean or POST /pages/1/clean
func (p *Pages) POSTClean {
    // do some work here
}

// DELETE /pages/clean or DELETE /pages/1/clean
func (p *Pages) DELETEClean {
    // do some work here
}

// GET /pages/stat or GET /pages/1/stat
func (p *Pages) GETStat {
    // do some work here
}

...

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func RenderJSON

func RenderJSON(w http.ResponseWriter, code int, s JSON)

RenderJSON common function to render JSON to client

func RenderJSONError

func RenderJSONError(w http.ResponseWriter, code int, s string)

RenderJSONError common function to render error to client in JSON format

func RenderJSONgzip

func RenderJSONgzip(w http.ResponseWriter, code int, s JSON)

RenderJSONgzip common function to render gzipped JSON to client

Types

type BaseModel

type BaseModel interface {
	ID() int64
	Valid() bool

	AddError(string, string)
	SetErrors(ModelErrors)
	GetErrors() ModelErrors
	ResetErrors()
}

BaseModel interface

type Controller

type Controller struct {
	Ctx
}

Controller contains request information (deprecated use flash.Ctx instead)

type Ctr

type Ctr interface {
	// contains filtered or unexported methods
}

Ctr public interface for Controller

type Ctx

type Ctx struct {
	Req *http.Request
	W   http.ResponseWriter

	Action string
	// contains filtered or unexported fields
}

Ctx contains request information

func (*Ctx) Cookie

func (c *Ctx) Cookie(s string) string

Cookie returns request header

func (*Ctx) Header

func (c *Ctx) Header(s string) string

Header returns request header

func (*Ctx) ID64

func (c *Ctx) ID64() int64

ID64 returns ID as int64

func (*Ctx) LoadFile

func (c *Ctx) LoadFile(field, dir string) (string, error)

LoadFile handling file uploads

func (*Ctx) LoadJSONRequest

func (c *Ctx) LoadJSONRequest(root string, v interface{})

LoadJSONRequest extracting JSON request by key from request body into interface

func (*Ctx) Param

func (c *Ctx) Param(k string) string

Param get URL param

func (*Ctx) Params

func (c *Ctx) Params() map[string]string

Params returns all URL params

func (*Ctx) QueryParam

func (c *Ctx) QueryParam(s string) string

QueryParam returns URL query param

func (*Ctx) Render

func (c *Ctx) Render(code int, b []byte)

Render rendering []byte to client

func (*Ctx) RenderError

func (c *Ctx) RenderError(code int, s string)

RenderError rendering error to client

func (*Ctx) RenderJSON

func (c *Ctx) RenderJSON(code int, s JSON)

RenderJSON rendering JSON to client

func (*Ctx) RenderJSONError

func (c *Ctx) RenderJSONError(code int, s string)

RenderJSONError rendering error to client in JSON format

func (*Ctx) RenderString

func (c *Ctx) RenderString(code int, s string)

RenderString rendering string to client

func (*Ctx) SetVar

func (c *Ctx) SetVar(k string, v interface{})

SetVar set session variable

func (*Ctx) Var

func (c *Ctx) Var(k string) interface{}

Var returns session variable

type JSON

type JSON map[string]interface{}

JSON shortcut for map[string]interface{}

type Model

type Model struct {
	Id int64 `json:"id"`
	ModelBase
}

Model structure for base model with ID included

type User struct {
    flash.Model
    Name string
}

func (*Model) ID

func (m *Model) ID() int64

ID returns ID of record

type ModelBase

type ModelBase struct {
	CreatedAt time.Time   `json:"createdAt"`
	UpdatedAt time.Time   `json:"updatedAt"`
	Errors    ModelErrors `sql:"-" json:"-"`
}

ModelBase structure for base model

type User struct {
    flash.ModelBase
    Name string
}

func (*ModelBase) AddError

func (m *ModelBase) AddError(f string, t string)

AddError adding error to record

func (*ModelBase) GetErrors

func (m *ModelBase) GetErrors() ModelErrors

GetErrors returns record errors

func (*ModelBase) IsValid

func (m *ModelBase) IsValid() bool

IsValid returns true if no errors on record

func (*ModelBase) ResetErrors

func (m *ModelBase) ResetErrors()

ResetErrors clean all model errors

func (*ModelBase) SetErrors

func (m *ModelBase) SetErrors(e ModelErrors)

SetErrors set record errors

func (*ModelBase) Valid

func (m *ModelBase) Valid() bool

Valid placeholder for validation function

func (u *User) Valid() bool {
	u.ValidatePresence("Name", u.Name)
	return u.IsValid()
}

func (*ModelBase) ValidateFloat32

func (m *ModelBase) ValidateFloat32(f string, v, min, max float32)

ValidateFloat32 validates float32 min, max. -1 for any

m.ValidateFloat32("number", 10.2, -1, 11)

func (*ModelBase) ValidateFloat64

func (m *ModelBase) ValidateFloat64(f string, v, min, max float64)

ValidateFloat64 validates float64 min, max. -1 for any

m.ValidateFloat64("number", 10.2, -1, 11)

func (*ModelBase) ValidateFormat

func (m *ModelBase) ValidateFormat(f, v, reg string)

ValidateFormat validates string format with regex string

m.ValidateFormat("ip address", u.IP, `\A(\d{1,3}\.){3}\d{1,3}\z`)

func (*ModelBase) ValidateInt

func (m *ModelBase) ValidateInt(f string, v, min, max int)

ValidateInt validates int min, max. -1 for any

m.ValidateInt("number", 10, -1, 11)  // max 18

func (*ModelBase) ValidateInt64

func (m *ModelBase) ValidateInt64(f string, v, min, max int64)

ValidateInt64 validates int64 min, max. -1 for any

m.ValidateInt64("number", 10, 6, -1) // min 6

func (*ModelBase) ValidateLength

func (m *ModelBase) ValidateLength(f, v string, min, max int)

ValidateLength validates string min, max length. -1 for any

m.ValidateLength("password", m.Password, 6, 18) // min 6, max 18

func (*ModelBase) ValidatePresence

func (m *ModelBase) ValidatePresence(f, v string)

ValidatePresence validates string for presence

m.ValidatePresence("Name", m.Name)

type ModelErrors

type ModelErrors map[string][]string

ModelErrors errors type

type ReqFunc

type ReqFunc func(*Ctx) bool

ReqFunc is the function type for middlware

type Route

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

Route storing route information

func (*Route) FileServer

func (r *Route) FileServer(path string, b ...bool)

FileServer provides static files serving ex:

r := api.NewRouter()
dirIndex := false
preferGzip := false
r.PathPrefix("/images/").FileServer("./public", dirIndex, preferGzip)

where

  • dirIndex specifying if it should display directory content or not
  • preferGzip specifying if it should look for gzipped file version

func (*Route) HandleFunc

func (r *Route) HandleFunc(s string, f func(http.ResponseWriter, *http.Request))

HandleFunc setting function to handle route

func (*Route) Handler

func (r *Route) Handler(handler http.Handler) *Route

Handler sets a handler for the route.

func (*Route) HandlerFunc

func (r *Route) HandlerFunc(f func(http.ResponseWriter, *http.Request)) *Route

HandlerFunc sets a handler function for the route.

func (*Route) NewRoute

func (r *Route) NewRoute(prefix string) *Route

NewRoute registers an empty route.

func (*Route) Resource

func (r *Route) Resource(path string, i Ctr, funcs ...ReqFunc)

Resource registers a new route with a matcher for URL path and registering controller handler ex:

r := api.NewRouter()
api = r.PathPrefix("/api/v1")
api.Resource("/pages", &PagesController{}, AuthFunc)

where

  • PagesController is the type implementing Controller
  • AuthFunc is middleware function that implements ReqFunc.

func (*Route) Route

func (r *Route) Route(path string, f handlerFunc, funcs ...ReqFunc)

Route registers a new route with a matcher for URL path ex:

r := api.NewRouter()
api = r.PathPrefix("/api/v1")
api.Route("/pages/:id/comments", PageComments, AuthFunc)

where

  • PageComments is the function implementing func(*flash.Ctx)
  • AuthFunc is middleware function that implements ReqFunc.

type Router

type Router struct {

	// SSL defines server type (default none SSL)
	SSL bool
	// PublicKey for SSL processing
	PublicKey string
	// PrivateKey for SSL processing
	PrivateKey string
	// contains filtered or unexported fields
}

Router stroring app routes structure

func NewRouter

func NewRouter() *Router

NewRouter creates new Router

func (*Router) HandleFunc

func (r *Router) HandleFunc(path string, f func(http.ResponseWriter, *http.Request))

HandleFunc registers a new route with a matcher for the URL path. See Route.HandlerFunc().

func (*Router) HandlePrefix

func (r *Router) HandlePrefix(path string, handler http.Handler)

HandlePrefix registers a new handler to serve prefix

func (*Router) NewRoute

func (r *Router) NewRoute(prefix string) *Route

NewRoute registers an empty route.

func (*Router) PathPrefix

func (r *Router) PathPrefix(s string) *Route

PathPrefix create new prefixed group for routes

func (*Router) Resource

func (r *Router) Resource(path string, i Ctr, funcs ...ReqFunc)

Resource registers a new Resource with a matcher for URL path and registering controller handler

func (*Router) Route

func (r *Router) Route(path string, f handlerFunc, funcs ...ReqFunc)

Route registers a new route with a matcher for URL path and registering controller handler

func (*Router) Serve

func (r *Router) Serve(bind string)

Serve starting http server

func (*Router) ServeHTTP

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP dispatches the handler registered in the matched route.

Jump to

Keyboard shortcuts

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