Skip to content

vtg/flash2

Repository files navigation

flash2

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 := flash2.NewRouter()

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

// auto generates controller routes
r.Controller("/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 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/flash2"
)

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 := flash2.NewRouter()
	a := r.PathPrefix("/api/v1")

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

// simple quthentication implementation
func auth(c *flash2.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{}

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

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

	c.RenderJSON(200, flash2.JSON{"pages": res})
}

// Show processed on GET /pages/1
func (p Pages) Show(c *flash2.Ctx) {
	page := findPage(c.Params.Int64("id"))

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

	c.RenderJSON(200, flash2.JSON{"page": page})
}

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

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

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

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

// Destroy processed on DELETE /pages/1
func (p Pages) Destroy(c *flash2.Ctx) {
	page := findPage(c.Params.Int64("id"))

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

	delete(pages, page.Id)
	c.RenderJSON(203, "")
}

// ActivateGET custom non crud action activates/deactivated page. processed on GET /pages/1/activate
func (p Pages) ActivateGET(c *flash2.Ctx) {
	page := findPage(c.Params.Int64("id"))
	if page == nil {
		c.RenderJSONError(404, "record not found")
		return
	}

	page.Visible = !page.Visible
	c.RenderJSON(200, flash2.JSON{"page": page})
}

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

 // POST /pages/clean or POST /pages/1/clean
 func (p Pages) CleanPOST {
   // do some work here
 }
 // DELETE /pages/clean or DELETE /pages/1/clean
 func (p Pages) CleanDELETE {
   // do some work here
 }
 // GET /pages/stat or GET /pages/1/stat
 func (p Pages) StatGET {
   // do some work here
 }
 ...

#####Author

VTG - http://github.com/vtg

License

Released under the MIT License.

GoDoc

About

fast web framework for go to create json API applications

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages