/gem

Gem is an easy to use and high performance web framework written in Go(golang), support HTTP/2, and provides leveled logger and frequently used middlewares.

Primary LanguageGoBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

Gem Web Framework GoDoc Build Status Go Report Card Coverage Status Join the chat at https://gitter.im/go-gem/gem

Gem is an easy to use and high performance web framework written in Go(golang), it supports HTTP/2, and provides leveled logger and frequently used middlewares, note: requires go1.8 or above.

The current version is 2.0.0-beta, the old version v1 is deprecated, see changes. The APIs is currently unstable until the stable version 2.0.0 and go1.8 being released.

Features

Getting Started

Install

This package requires go1.8 or above.

$ go get -u github.com/go-gem/gem

Quick Start

package main

import (
    "log"

    "github.com/go-gem/gem"
)

func index(ctx *gem.Context) {
    ctx.HTML(200, "hello world")
}

func main() {
    // Create server.
    srv := gem.New(":8080")
    
    // Create router.
    router := gem.NewRouter()
    // Register handler
    router.GET("/", index)
    
    // Start server.
    log.Println(srv.ListenAndServe(router.Handler()))
}

Context

Context embedded http.ResponseWriter and *http.Request, and provides some useful APIs and shortcut, see https://godoc.org/github.com/go-gem/gem#Context.

Logger

AFAIK, the following leveled logging packages are compatible with Gem web framework:

  • logrus - structured, pluggable logging for Go
  • go-logging - golang logging library
  • gem-log - default logger
  • Please let me know if I missed the other logging packages :)

Logger includes four levels: debug, info, error and fatal,

APIs

  • Debug and Debugf
  • Info and Infof
  • Error and Errorf
  • Fatal and Fatalf

We take logrus as example to show that how to set and use logger.

// set logrus logger as server's logger.
srv.SetLogger(logrus.New())

// we can use it in handler.
router.GET("/logger", func(ctx *gem.Context) {
		ctx.Logger().Debug("debug")
		ctx.Logger().Info("info")
		ctx.Logger().Error("error")
})

Static Files

router.ServeFiles("/tmp/*filepath", http.Dir(os.TempDir()))

Note: the first parameter must end with *filepath.

REST APIs

The router is friendly to REST APIs.

// user list
router.GET("/users", func(ctx *gem.Context) {
    ctx.JSON(200, userlist)    
})

// add user
router.POST("/users", func(ctx *gem.Contexy) {
    ctx.Request.ParseForm()
    name := ctx.Request.FormValue("name")
    
    // add user
    
    ctx.JSON(200, msg)
})

// user profile.
router.GET("/users/:name", func(ctx *gem.Context) {
    // firstly, we need get the username from the URL query.
    name, err := gem.String(ctx.UserValue("name"))
    if err != nil {
        ctx.JSON(404, userNotFound)
        return
    }
    
    // return user profile.
    ctx.JSON(200, userProfileByName(name))
})

// update user profile
router.PUT("/users/:name", func(ctx *gem.Context) {
    // firstly, we need get the username from the URL query.
    name, err := gem.String(ctx.UserValue("name"))
    if err != nil {
        ctx.JSON(404, userNotFound)
        return
    }
    
    // get nickname
    ctx.Request.ParseForm()
    nickname := ctx.Request.FormValue("nickname")
    
    // update user nickname.
    
    ctx.JSON(200, msg)
})

// delete user
router.DELETE("/users/:name", func(ctx *gem.Context) {
    // firstly, we need get the username from the URL query.
    name, err := gem.String(ctx.UserValue("name"))
    if err != nil {
        ctx.JSON(404, userNotFound)
        return
    }
    
    // delete user.
    
    ctx.JSON(200, msg)
}

HTTP/2 Server Push

See https://github.com/go-gem/examples/tree/master/http2.

router.GET("/", func(ctx *gem.Context) {
	if err := ctx.Push("/images/logo.png", nil); err != nil {
		ctx.Logger().Info(err)
	}

	ctx.HTML(200, `<html><head></head><body><img src="/images/logo.png"/></body></html>`)
})
router.ServeFiles("/images/*filepath", http.Dir(imagesDir))

Use Middleware

It is easy to implement a middleware, see Middleware interface, you just need to implement the Wrap function.

type Middleware interface {
    Wrap(next Handler) Handler
}

For example, we defined a simple debug middleware:

type Debug struct{}

// Wrap implements the Middleware interface.
func (d *Debug) Wrap(next gem.Handler) gem.Handler {
    // gem.HandlerFunc is adapter like http.HandlerFunc.
	return gem.HandlerFunc(func(ctx *gem.Context) {
		// print request info.
		log.Println(ctx.Request.URL, ctx.Request.Method)

		// call the next handler.
		next.Handle(ctx)
	})
}

and then we should register it:

register the middleware for all handlers via Router.Use.

router.Use(&Debug{})

we can also register the middleware for specific handler via HandlerOption.

router.GET("/specific", specificHandler, &gem.HandlerOption{Middlewares:[]gem.Middleware{&Debug{}}})

Gem also provides some frequently used middlewares, see Middlewares.

Share data between middlewares

Context provides two useful methods: SetUserValue and UserValue to share data between middlewares.

// Store data into context in one middleware
ctx.SetUserValue("name", "foo")

// Get data from context in other middleware or hander
ctx.UserValue("name")

Middlewares

Please let me know that you composed some middlewares, I will mention it here, I believe it would be helpful to users.

Semantic Versioning

Gem follows semantic versioning 2.0.0 managed through GitHub releases.

Support Us

  • ⭐ the project.
  • Spread the word.
  • Contribute to the project.

Contribute

We’re always looking for help, so if you would like to contribute, we’d love to have you!

Changes

The v2 and v1 are totally different:

  • v2 built on top of net/http.

  • v2 require go1.8 or above.

  • v2 is compatible with Windows.

FAQ

  • Why choose net/http instead of fasthttp?

    1. net/http has much more third-party packages than fasthttp.

    2. fasthttp doesn't support HTTP/2 yet.

LICENSE

BSD 3-Clause License, see LICENSE and AUTHORS.

Inspiration & Credits

For respecting the third party packages, I added their author into AUTHORS, and listed those packages here.

  • httprouter - LICENSE. Gem's router is a custom version of httprouter, thanks to httprouter.