Home

Awesome

#Neko wercker status GoDoc GoCover

A lightweight web application framework for Golang

NOTE: Neko is still under development, so API might be changed in future.

Features

Getting Started

Basic usage

package main
import "github.com/rocwong/neko"
func main() {
  app := neko.Classic()
  app.GET("/", func(ctx *neko.Context)  {
      ctx.Text("Hello world!")
  })
  app.Run(":3000")
}

Initial Neko without middlewares

app := neko.New()
app.Use(neko.Logger())
app.Use(neko.Recovery())

##Routing Using GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS and Any

app.GET("/get", get)
app.POST("/post", post)
app.PUT("/put", put)
app.PATCH("/patch", patch)
app.DELETE("/delete", delete)
app.HEAD("/head", head)
app.OPTIONS("/options", options)
// A shortcut for all request methods
app.Any("/any", options)

Neko uses julienschmidt's httprouter internaly.

##Group Routing

v1 := app.Group("/v1", func(router *neko.RouterGroup) {
  // Match /v1/item
  router.GET("/item", item)

  // Nested group
  router.Group("/sub", func(sub *neko.RouterGroup) {
    // Match /v1/sub/myitem
    sub.GET("/myitem", myitem)
  })
})
// Match /v1/act
v1.GET("/act", act)

Parameters

####Parameters in path

app.GET("/user/:name/*age", func(ctx *neko.Context) {
  // Request: "/user/neko/1?name=none&food=fish"
  
  name := ctx.Params.ByGet("name")
  age := ctx.Params.ByGet("age")
  food := ctx.Params.ByGet("food")
  
  // Response: neko is 1, eat fish
  ctx.Text(name + " is " + age + ", eat " + ctx.Params.ByGet("eat"))
})

####Multipart/Urlencoded Form

app.POST("/user", func(ctx *neko.Context) {
  // Request: "/user"  Post Data: { name: neko, age: 1}
  
  // Response: neko is 1
  ctx.Text(ctx.Params.ByPost("name") + " is " + ctx.Params.ByPost("age"))
})

####Json Data

app.POST("/user", func(ctx *neko.Context) {
  // Request: "/user"  Post Data: { name: neko, age: 1} Content-type: "application/json"
  
  // Only get once
  dataJson := ctx.Params.Json()
  
  // Response: neko is 1
  ctx.Text(dataJson.GetString("name") + " is " + dataJson.Get("age"))
  
  // dataJson.Get(param) : return type interface {}
  // dataJson.GetString(param) : return type string
  // dataJson.GetInt32(param) : return type int32
  // dataJson.GetUInt32(param) : return type uint32
  // dataJson.GetFloat32(param) : return type float32
  // dataJson.GetFloat64(param) : return type float64
})

####BindJSON

type User struct {
  User     string
  Password string
}
app.POST("/user", func(ctx *neko.Context) {
  // Request: "/user"  Post Data: { name: neko, password: abcdefg} Content-type: "application/json"
  var json User
  if ctx.Params.BindJSON(&json) == nil {
    // Response: neko's password abcdefg
    ctx.Text(json.Name + "'s password " + json.Password)
  }
})

##Response

####Render

type ExampleXml struct {
  XMLName xml.Name `xml:"example"`
  One     string   `xml:"one,attr"`
  Two     string   `xml:"two,attr"`
}

// Response: <example one="hello" two="xml"/>
ctx.Xml(ExampleXml{One: "hello", Two: "xml"})
// Response: {"msg": "json render", "status": 200}
ctx.Json(neko.JSON{"msg": "json render", "status": 200})

// Response: neko({"msg": "json render", "status": 200})
ctx.Jsonp("neko", neko.JSON{"msg": "json render", "status": 200})

// Response: neko text
ctx.Text("neko text")

####Redirect

// Default 302
ctx.Redirect("/")

// Redirect 301
ctx.Redirect("/", 301)

####Headers

// Get header
ctx.Writer.Header()

// Set header
ctx.SetHeader("x-before", "before")

##Cookie

app.GET("/", func (ctx *neko.Context) {
  ctx.SetCookie("myvalue", "Cookies Save")
  ctx.Text("Cookies Save")
})

app.GET("/get", func (ctx *neko.Context) {
  ctx.Text(ctx.GetCookie("myvalue"))
})

####Secure cookie

// Set cookie secret
app.SetCookieSecret("secret123")

app.GET("/set-secure", func (ctx *neko.Context) {
  ctx.SetSecureCookie("sv", "Cookies Save")
  ctx.Text("Cookies Save")
})

app.GET("/get-secure", func (ctx *neko.Context) {
  ctx.Text(ctx.GetSecureCookie("sv"))
})

Use following arguments order to set more properties:

SetCookie/SetCookieSecret(name, value [, MaxAge, Path, Domain, Secure, HttpOnly]).

Middlewares

####Using middlewares

// Global middlewares
app.Use(neko.Logger())

// Per route middlewares, you can add as many as you desire.
app.Get("/user", mymiddleware(), mymiddleware2(), user)

// Pass middlewares to groups
v1 := app.Group("/v1", func(router *neko.RouterGroup) {
  router.GET("/item", item)
}, mymiddleware1(), mymiddleware2(), mymiddleware3())

v1.Use(mymiddleware4)

####Custom middlewares

func mymiddleware() neko.HandlerFunc {
  return func (ctx *neko.Context) {
    // Before request
    t := time.Now()

    ctx.Next()

    // After request
    latency := time.Since(t)
    log.Print(latency)

    // Access the status we are sending
    status := ctx.Writer.Status()
    log.Println(status)
  }
}

More middleware

For more middleware and functionality, check out the repositories in the neko-contrib organization.

Others

// Static Serves
app.Static("/static", "content/static")

// Get Remote IP Address
app.GET("/", func (ctx *neko.Context) {
  ctx.ClientIP()
}

// Metadata Management
app.GET("/", func (ctx *neko.Context) {
  ctx.Set("foo", "bar")
  v, err := ctx.Get("foo")
  v = ctx.MustGet("foo")
}

Credits & Thanks

I use code/got inspiration from these excellent libraries:

License

Neko is licensed under the MIT