An ideally refined web framework for Go.



GitHub Actions codecov Go Report Card PkgGoDev

An ideally refined web framework for Go.

High-performance? Fastest? Almost all web frameworks are using these words to tell people that they are the best. Maybe they are, maybe not. Air does not intend to follow the crowd. Our goal is always to strive to make it easy for people to use Air to build their web applications. So, we can only guarantee you one thing: Air can serve properly.


  • API
    • As less as possible
    • As clean as possible
    • As simple as possible
    • As expressive as possible
  • Server
    • HTTP/2 (h2 & h2c) support
    • SSL/TLS support
    • ACME support
    • PROXY (v1 & v2) support
    • Graceful shutdown support
  • Router
    • Based on the Radix Tree
    • Zero dynamic memory allocation
    • Blazing fast
    • Has a good inspection mechanism
    • Group routes support
  • Gas (aka middleware)
    • Router level:
      • Before router
      • After router
    • Route level
    • Group level
  • WebSocket
    • Full-duplex communication
  • Reverse proxy
    • Retrieves resources on behalf of a client from another server
    • Supported protocols:
      • HTTP
      • WebSocket
      • gRPC
  • Binder
    • Binds HTTP request body into the provided struct
    • Supported MIME types:
      • application/json
      • application/xml
      • application/protobuf
      • application/msgpack
      • application/toml
      • application/yaml
      • application/x-www-form-urlencoded
      • multipart/form-data
  • Renderer
    • Rich template functions
    • Hot update support
  • Minifier
    • Minifies HTTP response on the fly
    • Supported MIME types:
      • text/html
      • text/css
      • application/javascript
      • application/json
      • application/xml
      • image/svg+xml
  • Gzip
    • Compresses HTTP response by using the gzip
    • Default MIME types:
      • text/plain
      • text/html
      • text/css
      • application/javascript
      • application/json
      • application/xml
      • application/toml
      • application/yaml
      • image/svg+xml
  • Coffer
    • Accesses binary asset files by using the runtime memory
    • Significantly improves the performance of the air.Response.WriteFile
    • Asset file minimization and gzip support
    • Default asset file extensions:
      • .html
      • .css
      • .js
      • .json
      • .xml
      • .toml
      • .yaml
      • .yml
      • .svg
      • .jpg
      • .jpeg
      • .png
      • .gif
    • Hot update support
  • I18n
    • Adapt to the request's favorite conventions
    • Implanted into the air.Response.Render
    • Hot update support
  • Error
    • Centralized handling


Open your terminal and execute

$ go get


The only requirement is the Go, at least v1.13.

Hello, 世界

Create a file named hello.go

package main

import ""

func main() {
	air.Default.GET("/", func(req *air.Request, res *air.Response) error {
		return res.WriteString("Hello, 世界")

and run it

$ go run hello.go

then visit http://localhost:8080.


Does all web frameworks need to have a complicated (or a lovely but lengthy) website to guide people how to use them? Well, Air has only one Doc with useful comments. In fact, Air is so succinct that you don't need to understand how to use it through a large document.


As we all know that the air of Earth is a mixture of gases. So the same is that Air adopts the gas as its composition. Everyone can create new gas and use it within Air simply.

A gas is a function chained in the HTTP request-response cycle with access to the air.Request and air.Response which it uses to perform a specific action, for example, logging every request or recovering from panics.

return func(next air.Handler) air.Handler {
	return func(req *air.Request, res *air.Response) error {
		// Do something here...
		return next(req, res) // Execute the next handler

If you already have some good HTTP middleware, you can simply wrap them into gases by calling the air.WrapHTTPMiddleware.

If you are looking for some useful gases, simply visit here.


If you want to be familiar with Air as soon as possible, simply visit here.


Why named Air?

"A" for "An", "I" for "Ideally" and "R" for "Refined". So, Air.

Why based on the net/http?

In fact, I've tried to implement a full-featured HTTP server (just like the awesome valyala/fasthttp). But when I finished about half of the work, I suddenly realized: What about stability? What about those awesome middleware outside? And, seriously, what am I doing?

Why not just use the net/http?

Yeah, we can of course use the net/http directly, after all, it can meet many requirements. But, ummm... it's really too stable, isn't it? I mean, to ensure Go's backward compatibility (which is extremely necessary), we can't easily add some handy features to the net/http. And, the http.Request does not only represents the request received by the server, but also represents the request made by the client. In some cases it can be confusing. So why not just use the net/http as the underlying server, and then implement a refined web framework that are only used for the server-side on top of it?

Do you know we already got the gin-gonic/gin and labstack/echo?

Of course, I knew it when I started Go. And, I love both of them! But, why not try some new flavors? Are you sure you prefer them instead of Air? Don't even give Air a try? Wow... well, maybe Air is not for you. After all, it's for people who love to try new things. Relax and continue to maintain the status quo, you will be fine.

What about the fantastic Gorilla web toolkit?

Just call the air.WrapHTTPHandler and air.WrapHTTPMiddleware.

Is Air good enough?

Far from enough. But it's already working.


If you want to discuss Air, or ask questions about it, simply post questions or ideas here.


If you want to help build Air, simply follow this to send pull requests here.


This project is licensed under the MIT License.

License can be found here.

  • Dependency Headaches: some things aren't importing for reasons unknown

    Dependency Headaches: some things aren't importing for reasons unknown

    Simply cannot import /text/langauge for some reason.

    go version
         go version go1.11.2 windows/amd64
    go get -u
         go: finding latest
         go get no matching versions for query "latest"

    on my DigitalOcean Debian server, there's been some trouble with these:

    go:[email protected]: go.mod has non-.../v2 module path "" (and .../v2/go.mod does not exist) at revision v2.3.7
    go: error loading module requirements

    though on my windows devbox it works fine.

    on a side note, massive updates today, wow! This project is growing and getting better everyday 😲, it's hard to keep up lol. But it's all good, many of the changes in the last day have been breaking (to me at least), so I'm going to stick to the vanilla version as it is and simply write my extentions in an extention.go file as I see no reason to tediously duplicate all the awesome progress and developments you're driving.

    The only reason for my fork was to add a couple of convenience features, like:

    • native msgpack support in binder.go and response.go
    • req.Query("param") is a nice to have feature
    • .SetCookie(name, http.Cookie), or, gin style .SetCookie(name, all_the_params_laid_flat...)
    • req.Cookie(name) -> string, and, req.GetCookie(name) -> *Cookie
    • Coffer Gzip support, and Gzip support generally
    • Streaming, which got solved already, thanks 👍
    • Plain http middleware support
      • specifically: throttled, which could make for a nice gas
    • +Various Header methods that make life easier.
    • cache-control related concerns, autocert things
    • HostWhiteList stuff, redirecting localhost to the main domain when in debug mode which was annoying, I wish there was a toggle.

    And I see you've added many of these features already, so I'm wondering if perhaps we could reach consensus on some of these features so that they can potentially be integrated and made official.

    opened by SaulDoesCode 50
  • Cookies Go Missing when they're set before a redirect

    Cookies Go Missing when they're set before a redirect

    air.GET("/auth/:verifier", func(req *air.Request, res *air.Response) error {
    	user, err := VerifyUser(req.Param("verifier").Value().String())
    	if err != nil || user == nil {
    		if DevMode {
    			fmt.Println("Unable to Authenticate user: ", err)
    		return UnauthorizedError.Send(res)
    	newtoken, err := GenerateAuthToken(user, false)
    	if err == nil {
    // This Cookie never reaches the client
    		res.SetCookie("Auth", &air.Cookie{
    			Value:    newtoken,
    			Path:     "/",
    			MaxAge:   60 * 60 * 24 * 7,
                            Domain: AppDomain,
    			HTTPOnly: !DevMode,
    			Secure:   !DevMode,
    	} else {
    		if DevMode {
    			fmt.Println("error verifying the user, GenerateAuthToken db problem: ", err)
    	if user.isAdmin() {
    		return res.Redirect("/admin")
    	return res.Redirect("/")

    the problem is probably somewhere in res.Write, but it looks like the Header application step of serving is ignored when content io.ReadSeeker is nil, or something else is happening, not sure. But I need cookies to set on redirects, it worked in echo, it should work here.

    opened by SaulDoesCode 4
  • Add MsgPack support

    Add MsgPack support

    vmihailenco/msgpack has a fairly decent and easy to use golang msgpack implementation it would be great to see native support in air, I've used echo and gin in the past and it would have been nice to see msgpack being handled natively the same way JSON is.

    // WriteMsgPack responds to the client with the "application/msgpack" content v.
    func (r *Response) WriteMsgPack(v interface{}) error {
    	var (
    		b   []byte
    		err error
    	b, err = msgpack.Marshal(v)
    	if err != nil {
    		return err
    	r.Headers["content-type"] = &Header{
    		Name:   "content-type",
    		Values: []string{"application/msgpack"},
    	return r.WriteBlob(b)

    Also maybe there is a way to stream json and msgpack. Streaming might be more performant and memory efficient than writing blobs. But I'm not sure how to do it right and handle stream failures properly.

    I'm using these functions in my Gin application

    // SendMsgpack send a msgpack encoded response with a status code
    func SendMsgpack(c ctx, code int, msg interface{}) error {
    	c.Header("Content-Type", "application/msgpack")
    	return msgpack.NewEncoder(c.Writer).Encode(msg)
    // SendJSON send a json encoded response with a status code
    func SendJSON(c ctx, code int, msg interface{}) error {
    	c.Header("Content-Type", "application/json")
    	return json.NewEncoder(c.Writer).Encode(msg)

    ps. air 很牛,真的,谢谢你创造它

    opened by SaulDoesCode 4
  • Need Configuration Variable for Email in autocert.Manager{}

    Need Configuration Variable for Email in autocert.Manager{}

    acm := autocert.Manager{
        Prompt: autocert.AcceptTOS,
        Cache:  autocert.DirCache(ACMECertRoot),
    if MaintainerEmail != "" {
      acm.Email = MaintainerEmail

    In the TOML maybe allow users to add maintainer_email

    opened by SaulDoesCode 2
  • Certificate on has expired

    Certificate on has expired

    The redirect from to currently flags an error in my browser as the certificate issued by Lets Encrypt is only valid until the 2nd of June 2017. It seems the (auto)renewal of it has failed.

    opened by daenney 2
  • Support for OPTIONS & HEAD?

    Support for OPTIONS & HEAD?

    • OPTIONS is required for CORS Preflight:
    • HEAD is very useful for (custom) clients who want to check for the existence of a file without actually downloading it, e.g. link/image validation
    opened by LouisStAmour 1
  • How to write test becnhmark

    How to write test becnhmark

    func airHandler(req *air.Request, res *air.Response) error {
    	return nil
    func airHandlerWrite(req *air.Request, res *air.Response) error {
    	// io.WriteString(res, s)
    	return res.WriteString(req.Param("name").Value().String())
    func airHandlerTest(req *air.Request, res *air.Response) error {
    	return res.WriteString(req.Path)
    // func (a *air.Air) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // 	// a := air.New()
    // 	a.server.ServeHTTP(r, w)
    // }
    func loadAir(routes []route) http.Handler {
    	h := airHandler
    	if loadTestHandler {
    		h = airHandlerTest
    	app := air.New()
    	for _, r := range routes {
    		switch r.method {
    		case "GET":
    			app.GET(r.path, h)
    		case "POST":
    			app.POST(r.path, h)
    		case "PUT":
    			app.PUT(r.path, h)
    		case "PATCH":
    			app.PATCH(r.path, h)
    		case "DELETE":
    			app.DELETE(r.path, h)
    			panic("Unknow HTTP method: " + r.method)
    	return app
    func loadAirSingle(method, path string, h air.Handler) http.Handler {
    	app := air.New()
    	// app.Middleware.Skip(nil, h)
    	switch method {
    	case "GET":
    		app.GET(path, h)
    	case "POST":
    		app.POST(path, h)
    	case "PUT":
    		app.PUT(path, h)
    	case "PATCH":
    		app.PATCH(path, h)
    	case "DELETE":
    		app.DELETE(path, h)
    		panic("Unknow HTTP method: " + method)
    	return app


    ./router.go:557:6: cannot define new methods on non-local type air.Air
    ./router.go:559:3: a.server undefined (cannot refer to unexported field or method server)
    ./router.go:583:2: cannot use app (type *air.Air) as type http.Handler in return argument:
            *air.Air does not implement http.Handler (missing ServeHTTP method)
    ./router.go:604:2: cannot use app (type *air.Air) as type http.Handler in return argument:
            *air.Air does not implement http.Handler (missing ServeHTTP method)
    opened by dtmkeng 0
  • Code organization and API naming convention.

    Code organization and API naming convention.

    Writing Format

    1. 100 characters per line.
    2. Use <Tab> to indentation.
    3. A <Tab> occupies 8 spaces.
    4. Use // to comment.

    Code Organization

    1. Use gofmt to format all go files before git commit.


    1. Use go test to test whether the Air can server properly.
    opened by aofei 0
  • browser  return  application/octet-stream (0 byte)  when  url TrailingSlash

    browser return application/octet-stream (0 byte) when url TrailingSlash

    package main
    import (
    var a = air.Default
    func identicon(req *air.Request, res *air.Response) error {
     	return res.Write(bytes.NewReader(req.ParamValue("Name").Bytes()))
    func main() {
    	a.DebugMode = true
    	a.GET("/identicons/:Name", identicon)
    	a.Serve() //8080 

    visit http://localhost:8080/identicons/

    opened by tablecell 0
  • AutoPush needs more control

    AutoPush needs more control

    the <link> tag has several variations which don't always need pushing for example with preload/favicon pushing can disturb caching and cause needless bandwidth consumption and sometimes in the worst cases duplicate requests, so there should be a bit more specificity and potentially a feature to exclude/omit certain paths from the push list, (immutable/async cached assets assets that are very big)

    see transplacer's take on this matter.

    opened by SaulDoesCode 3
  • Gzip Support and cache-control headers

    Gzip Support and cache-control headers

    It would be very nice to see a golang web framework handle gzip natively and do it well. There are various libraries and middlewares out there which purport a well adjusted and performant solution to serving gzipped content.

    I've made a fairly primitive project some time ago, which provides an echo instance with the ability to read, monitor, cache and recache various static assets either within a specified folder or definitively located elsewhere; with this it would determine an asset's compress-ability and compress it thusly, serving it, thereby, only when a client's Accept-Encoding header indicates gzip support.

    Desireable Features In a Gzipping Sollution:

    • [ ] - Cache Gzipped Assets:

      • In memory, with coffer potentially.
        • watched assets, should, on changes, (asynchronously) re-compress/update a memory/disk backed asset.ext(.gz)
      • On Disk, like some nginx/apache configs permit.
        • eg. route localhost/asset.txt -> first looks for - > ./assets/.cache/asset.txt.gz
      • Client Side, by setting and maintaining the correct cache-control and etag headers.
    • [ ] - Compress at the highest level when caching, but automatically scale down with dynamic content.

    Air does not seem to handle caching headers, (to my knowledge, I may be wrong), as all my coffer cached assets seem to be missing their cache-control headers. While it would be possible to deliberately add such caching headers, it would certainly also have been nice had the air sub systems managed cache headers when it detected that the higher level user has not set any or has not deliberately disabled cache-control.

    opened by SaulDoesCode 5
Aofei Sheng
Try to glue everything together.
Aofei Sheng
Golanger Web Framework is a lightweight framework for writing web applications in Go.

/* Copyright 2013 All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except

golanger 299 Mar 3, 2022
Web framework for creating apps using Go in Google AppEngine

Welcome to app.go v3.0 app.go is a simple web framework for use in Google AppEngine. Just copy the app folder to your working folder and import it fro

George Nava 46 Mar 21, 2021
Eudore is the core of a golang lightweight web framework.

Eudore eudore是一个golang轻量级web框架核心,可以轻松扩展成一个技术栈专用框架,具有完整框架设计体系。 反馈和交流请加群组:QQ群373278915。 Features 易扩展:主要设计目标、核心全部解耦,接口即为逻辑。 简单:对象语义明确,框架代码量少复杂度低,无依赖库。 易用

null 72 Jun 15, 2022
Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.

Gin Web Framework Gin is a web framework written in Go (Golang). It features a martini-like API with performance that is up to 40 times faster thanks

Gin-Gonic 60.5k Jun 27, 2022
Goal is a toolkit for high productivity web development in Go language in the spirit of Revel Framework that is built around the concept of code generation.

Goal Goal is a set of tools for high productivity web development in Go language. Goal, being mostly inspired by Revel Framework and its discussions,

null 88 Sep 27, 2021
a golang web mvc framework, like mvc.

goku goku is a Web Mvc Framework for golang, mostly like ASP.NET MVC. doc & api Installation To install goku, simply run go get

QLeelulu 275 May 24, 2022
A high level web-framework for Go

go-start is a high level web-framework for Go, like Django for Python or Rails for Ruby. Installation: go get Documentatio

Erik Unger 264 May 31, 2022
A lightweight RESTful web framework for Go

Goweb A lightweight RESTful web framework for Go. For examples and usage, please read the Goweb API Documentation Read our Articles Who uses Goweb? "U

Stretchr, Inc. 630 May 10, 2022
Fast and Reliable Golang Web Framework

Gramework The Good Framework Gramework long-term testing stand metrics screenshot made with Gramework Stats Dashboard and metrics middleware What is i

null 368 Jun 11, 2022
Mango is a modular web-application framework for Go, inspired by Rack, and PEP333.

Mango Mango is a modular web-application framework for Go, inspired by Rack and PEP333. Note: Not actively maintained. Overview Mango is most of all a

Paul Bellamy 366 Jun 3, 2022
Classy web framework for Go

Martini NOTE: The martini framework is no longer maintained. Martini is a powerful package for quickly writing modular web applications/services in Go

Martini 11.5k Jun 29, 2022
A Go framework for building JSON web services inspired by Dropwizard

Tiger Tonic A Go framework for building JSON web services inspired by Dropwizard. If HTML is your game, this will hurt a little. Like the Go language

Richard Crowley 1k May 29, 2022
The web framework for Golang

uAdmin the Golang Web Framework Easy to use, blazing fast and secure. Originally open source by IntegrityNet Solutions and Services For Documentation:

uADMIN 193 May 30, 2022
Simple web framework for go, still quite beta at this point

WFDR Framework - Beta Release New 18/Feb/2012: Updated for go 1.0, new directory layout to take advantage of the go build tool. Background There's a m

null 23 Feb 11, 2021
A simple blog framework built with GO. Uses HTML files and a JSON dict to give you more control over your content.

Go-Blog A simple template based blog framework. Instructions Built for GO version: 1 See the Documentation or Getting Started pages in the wiki. Notes

Matt West 45 Feb 18, 2022
Goldorak GO is a mini framework for the Go programming language. (unfinished dead code)

Goldorak Go =========== > Goldorak GO ! Rétrolaser en action > Goldorak GO !! Va accomplir ta mission > Dans l'infini > Des galaxies > Poursuis ta lu

Bruno Michel 10 Apr 29, 2021
A small and evil REST framework for Go

go-rest A small and evil REST framework for Go Reflection, Go structs, and JSON marshalling FTW! go get import "

Erik Unger 125 Apr 18, 2022
🍐 Elegant Golang REST API Framework

An Elegant Golang Web Framework Goyave is a progressive and accessible web application framework focused on REST APIs, aimed at making backend develop

SystemGlitch 1.1k Jun 23, 2022
A lightweight MVC framework for Go(Golang)

utron utron is a lightweight MVC framework in Go (Golang) for building fast, scalable and robust database-driven web applications. Features Postgres,

Geofrey Ernest 2.2k Jun 24, 2022