A lightweight web application framework for Golang
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
render
test
.gitignore
LICENSE
README.md
context.go
context_test.go
helper.go
helper_test.go
logger.go
logger_test.go
neko.go
neko_test.go
recovery.go
recovery_test.go
response_writer.go
routergroup.go
routergroup_test.go
routerparams.go
routerparams_test.go
sessions.go
utils.go
wercker.yml

README.md

#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

  • Extremely simple to use.
  • RESTful support
  • Middleware support
  • Unlimited nested group routers.

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