An ideally refined web framework for Go.

Air

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.

Features

  • 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

Installation

Open your terminal and execute

$ go get github.com/aofei/air

done.

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

Hello, 世界

Create a file named hello.go

package main

import "github.com/aofei/air"

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

and run it

$ go run hello.go

then visit http://localhost:8080.

Documentation

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.

Gases

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.

Examples

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

FAQ

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.

Community

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

Contributing

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

License

This project is licensed under the MIT License.

License can be found here.

Owner
Aofei Sheng
Try to glue everything together.
Aofei Sheng
Comments
  • 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 golang.org/x/text/language
         go: finding golang.org/x/text/language latest
         go get golang.org/x/text/language: no matching versions for query "latest"
    

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

    go: github.com/tdewolff/minify/[email protected]: go.mod has non-.../v2 module path "github.com/tdewolff/minify" (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.

  • 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.

  • 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.Status(code)
    	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.Status(code)
    	c.Header("Content-Type", "application/json")
    	return json.NewEncoder(c.Writer).Encode(msg)
    }
    

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

  • Need Configuration Variable for Email in autocert.Manager{}

    Need Configuration Variable for Email in autocert.Manager{}

    https://github.com/aofei/air/blob/e62e9ff25eefecad7a97b37642bba8f5846bf035/server.go#L64

    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

  • Certificate on airwf.org has expired

    Certificate on airwf.org has expired

    The redirect from https://airwf.org to https://github.com/sheng/air 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.

  • Support for OPTIONS & HEAD?

    Support for OPTIONS & HEAD?

    • OPTIONS is required for CORS Preflight: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS
    • 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 https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD
  • 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)
    		default:
    			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)
    	default:
    		panic("Unknow HTTP method: " + method)
    	}
    
    	return app
    }
    

    Error

    ./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)
    
  • 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.

    Testing

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

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

    package main
    
    import (
    	"bytes"
     	"github.com/aofei/air"
     )
    
    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/

  • 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.

  • 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.

Flamingo Framework and Core Library. Flamingo is a go based framework for pluggable web projects. It is used to build scalable and maintainable (web)applications.
Flamingo Framework and Core Library. Flamingo is a go based framework for pluggable web projects. It is used to build scalable and maintainable (web)applications.

Flamingo Framework Flamingo is a web framework based on Go. It is designed to build pluggable and maintainable web projects. It is production ready, f

Jan 5, 2023
Golanger Web Framework is a lightweight framework for writing web applications in Go.

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

Nov 14, 2022
The jin is a simplified version of the gin web framework that can help you quickly understand the core principles of a web framework.

jin About The jin is a simplified version of the gin web framework that can help you quickly understand the core principles of a web framework. If thi

Jul 14, 2022
⚡ Rux is an simple and fast web framework. support middleware, compatible http.Handler interface. 简单且快速的 Go web 框架,支持中间件,兼容 http.Handler 接口

Rux Simple and fast web framework for build golang HTTP applications. NOTICE: v1.3.x is not fully compatible with v1.2.x version Fast route match, sup

Dec 8, 2022
Roche is a Code Generator and Web Framework, makes web development super concise with Go, CleanArch
Roche is a Code Generator and Web Framework, makes web development super concise with Go, CleanArch

It is still under development, so please do not use it. We plan to release v.1.0.0 in the summer. roche is a web framework optimized for microservice

Sep 19, 2022
A powerful go web framework for highly scalable and resource efficient web application

webfr A powerful go web framework for highly scalable and resource efficient web application Installation: go get -u github.com/krishpranav/webfr Exa

Nov 28, 2021
A powerful go web framework for highly scalable and resource efficient web application

A powerful go web framework for highly scalable and resource efficient web application

Oct 3, 2022
A web app built using Go Buffalo web framework

Welcome to Buffalo Thank you for choosing Buffalo for your web development needs. Database Setup It looks like you chose to set up your application us

Feb 7, 2022
re:Web enables classic web applications to run on AWS Lambda.
re:Web enables classic web applications to run on AWS Lambda.

re:Web re:Web enables classic web applications to run on AWS Lambda. re:Web interfaces with the Lambda Runtime API. It translates API Gateway requests

Jan 1, 2023
Chainrand contract + web frontend + web backend

Chainrand-web This repo contains the implementation of Chainrand. https://chainrand.io Smart Contract Contains functionality to tie a Chainlink VRF to

Dec 8, 2021
Gin is a HTTP web framework written in Go (Golang).
Gin is a HTTP web framework written in Go (Golang).

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.

Jan 3, 2023
An opinionated productive web framework that helps scaling business easier.
An opinionated productive web framework that helps scaling business easier.

appy An opinionated productive web framework that helps scaling business easier, i.e. focus on monolith first, only move to microservices with GRPC la

Nov 4, 2022
BANjO is a simple web framework written in Go (golang)

BANjO banjo it's a simple web framework for building simple web applications Install $ go get github.com/nsheremet/banjo Example Usage Simple Web App

Sep 27, 2022
beego is an open-source, high-performance web framework for the Go programming language.
beego is an open-source, high-performance web framework for the Go programming language.

Beego Beego is used for rapid development of enterprise application in Go, including RESTful APIs, web apps and backend services. It is inspired by To

Jan 1, 2023
High performance, minimalist Go web framework
High performance, minimalist Go web framework

Supported Go versions As of version 4.0.0, Echo is available as a Go module. Therefore a Go version capable of understanding /vN suffixed imports is r

Jan 2, 2023
⚡️ Express inspired web framework written in Go
⚡️ Express inspired web framework written in Go

Fiber is an Express inspired web framework built on top of Fasthttp, the fastest HTTP engine for Go. Designed to ease things up for fast development w

Jan 2, 2023
Go web framework with a natural feel

Fireball Overview Fireball is a package for Go web applications. The primary goal of this package is to make routing, response writing, and error hand

Nov 9, 2022
Gearbox :gear: is a web framework written in Go with a focus on high performance
Gearbox :gear: is a web framework written in Go with a focus on high performance

gearbox ⚙️ is a web framework for building micro services written in Go with a focus on high performance. It's built on fasthttp which is up to 10x fa

Jan 3, 2023