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.

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

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

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

Nov 7, 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 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

Jan 2, 2023
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,

Sep 27, 2021
a golang web mvc framework, like asp.net 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 github.com/QLeelulu/go

Dec 7, 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 github.com/ungerik/go-start Documentatio

Dec 24, 2022
A lightweight RESTful web framework for Go
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

Dec 12, 2022
Fast and Reliable Golang Web Framework
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

Dec 18, 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

Nov 17, 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

Dec 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

Dec 9, 2022
The web framework for Golang
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:

Dec 24, 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

Feb 11, 2021
:bullettrain_side: High-performance web server for Go.
:bullettrain_side: High-performance web server for Go.

Aero is a high-performance web server with a clean API. Installation go get -u github.com/aerogo/aero/... Usage Run this in an empty directory: aero -

Dec 8, 2022
package for building REST-style Web Services using Go

go-restful package for building REST-style Web Services using Google Go Code examples using v3 REST asks developers to use HTTP methods explicitly and

Jan 1, 2023
The easiest way to create web applications with Go

web.go web.go is the simplest way to write web applications in the Go programming language. It's ideal for writing simple, performant backend web serv

Dec 24, 2022
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

Sep 10, 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

Apr 29, 2021