Giter VIP home page Giter VIP logo

box's Introduction

Box

Build Status GoDoc GitHub release (latest SemVer)

Box is an HTTP router to speed up development. Box supports URL parameters, interceptors, magic handlers and introspection documentation.

Getting started

package main

import (
	"github.com/fulldump/box"
)

func main() {

    b := box.NewBox()

    b.HandleFunc("GET", "/hello", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("World!"))
    })

    b.ListenAndServe() // listening at http://localhost:8080

}

Sending JSON

b := box.NewBox()

type MyResponse struct {
    Name string
    Age  int
}

b.Handle("GET", "/hello", func(w http.ResponseWriter, r *http.Request) MyResponse {
    return MyResponse{
        Name: "Fulanez",
        Age:  33,
    }
})

URL parameters

b := box.NewBox()

b.Handle("GET", "/articles/{article-id}", func(w http.ResponseWriter, r *http.Request) string {
    articleID := box.Param(r, "article-id")
    return "ArticleID is " + articleID
})

Receiving and sending JSON

type CreateArticleRequest struct {
    Title string
    Text  string
}

type Article struct {
    Id      string    `json:"id"`
    Title   string    `json:"title"`
    Text    string    `json:"text"`
    Created time.Time `json:"created"`
}

b := box.NewBox()
b.Handle("POST", "/articles", func(input CreateArticleRequest) Article {
    fmt.Println("Persist new article...", input)
    return Article{
        Id:      "my-new-id",
        Title:   input.Title,
        Text:    input.Text,
        Created: time.Unix(1674762079, 0),
    }
})

Use interceptors

Interceptors, also known as middlewares, are pieces of code that are executed in order before the handler to provide common functionality:

  • Do things before and/or after the handler execution
  • Cut the execution and stop executing the rest of interceptors and handler
  • Inject items into the context
func ListArticles()   { /* ... */ }
func CreateArticles() { /* ... */ }
func GetArticle()     { /* ... */ }
func DeleteArticle()  { /* ... */ }

func main() {
    b := box.NewBox()

    b.Use(box.AccessLog)   // use middlewares to print logs
    b.Use(box.PrettyError) // use middlewares return pretty errors

    b.Handle("GET", "/articles", ListArticles)
    b.Handle("POST", "/articles", CreateArticles)
    b.Handle("GET", "/articles/{article-id}", GetArticle)
    b.Handle("DELETE", "/articles/{article-id}", DeleteArticle)
}

Error handling

b := box.NewBox()
b.Use(box.PrettyError)
b.Handle("GET", "/articles", func() (*Article, error) {
    return nil, errors.New("could not connect to the database")
})
go b.ListenAndServe()

resp, _ := http.Get(s.URL + "/articles")
io.Copy(os.Stdout, resp.Body) // could not connect to the database

Groups

Groups are a neat way to organize and compose big APIs and also to limit the scope of interceptors.

b := box.NewBox()

v0 := b.Group("/v0")
v0.Use(box.SetResponseHeader("Content-Type", "application/json"))

v0.Handle("GET", "/articles", ListArticles)
v0.Handle("POST", "/articles", CreateArticle)

Custom interceptors

Interceptors are very useful to reuse logic in a very convenient and modular way.

Here is a sample interceptor that does nothing:

func MyCustomInterceptor(next box.H) box.H {
	return func(ctx context.Context) {
        // do something before the handler
		next(ctx) // continue the flow
		// do something after the handler
	}
}

The following interceptor returns a Server header:

func MyCustomInterceptor(next box.H) box.H {
	return func(ctx context.Context) {
		w := box.GetResponse(ctx)
		w.Header().Set("Server", "MyServer")
		next(ctx) // continue the flow
	}
}

func main() {

	b := box.NewBox()
	b.Use(MyCustomInterceptor)

}

Parametrized interceptors

Sometimes interceptors can be generalized to cover a wider set of use cases. For example, the following interceptor can set any response header and can be used multiple times.

func SetResponseHeader(key, value string) box.I {
	return func(next box.H) box.H {
		return func(ctx context.Context) {
			box.GetResponse(ctx).Header().Set(key, value)
			next(ctx)
		}
	}
}

func main() {
    b := box.NewBox()
    b.Use(
        box.SetResponseHeader("Server", "My server name"),
        box.SetResponseHeader("Version", "v3.2.1"),
    )
}

Generate OpenAPI from your API

Leverage all the API information you have already defined with Box to generate your OpenAPI specification, including your types.

Just use the function boxopenapi.Spec and publish your spec:

func main() {
	b := box.NewBox()
	// ... define all your handlers

	spec := boxopenapi.Spec(b)
	spec.Info.Title = "My service"
	spec.Info.Version = "1.0"
	spec.Servers = []boxopenapi.Server{
		{
			Url: "http://localhost:8080",
		},
	}

	b.Handle("GET", "/openapi.json", func() any {
		return spec
	})
}

box's People

Contributors

fulldump avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.