bellt

package module
Version: v0.0.0-...-d00c568 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 18, 2020 License: MIT Imports: 7 Imported by: 0

README

Bellt

Simple Golang HTTP router

Mentioned in Awesome Go Go Report Card codecov Build Status GitHub GoDoc

Bellt Package implements a request router with the aim of managing controller actions based on fixed and parameterized routes.

The project so far has the following functionalities:

  • Standard definition of route "/ health", in order to prepare the service developed with bellt to act as microservice.
  • Providing the creation of parameterized routes, simple or segmented (groups).
  • All requests can be made through fixed patterns, querystrings and parameters.
  • Obtaining the requisition parameters in the controller functions.

Summary

Install

To get Bellt

> Go CLI
go get -u github.com/GuilhermeCaruso/bellt
> Go DEP
dep ensure -add github.com/GuilhermeCaruso/bellt
> Govendor
govendor fetch github.com/GuilhermeCaruso/bellt

Guide

Router

To initialize our router

var router = bellt.NewRouter()
package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/GuilhermeCaruso/bellt"
)

func main() {
	router := bellt.NewRouter()

	log.Fatal(http.ListenAndServe(":8080", nil))
}

HandleFunc

HandleFunc function responsible for initializing a common route or built through the Router. All non-grouped routes must be initialized by this method.

/*
	[path] - Endpoint string
	[handlerFunc] - Function that will be called on the request
	[methods] - Slice for endpoint methods ("GET", "POST", "PUT", "DELETE")
*/

router.HandleFunc(path, handlerFunc, methods)
    
package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/GuilhermeCaruso/bellt"
)

func main() {
	router := bellt.NewRouter()

	router.HandleFunc("/bellt", belltHandler, "GET")

	log.Fatal(http.ListenAndServe(":8080", nil))
}

func belltHandle(w http.ResponseWriter, r *http.Request){
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("Simple Golang HTTP router")
}

HandleGroup

HandleGroup is responsible for creating a group of routes. The main path can be set for all other routes.

/*
	[mainPath] - Main route used in all subr-outes
	
	[subHandleFunc] - SubHandleFunc function responsiblefor initializing a common route or
	built through the Router. All grouped routes must be initialized by this method
*/

router.HandleGroup(mainPath, ...SubHandleFunc)
    
SubHandleFunc

SubHandleFunc is responsible for initializing a common or built route. Its use must be made within the scope of the HandleGroup method, where the main path will be declared.

/*
	[path] - Endpoint string
	[handlerFunc] - Function that will be called on the request
	[methods] - Slice for endpoint methods ("GET", "POST", "PUT", "DELETE")
*/

router.SubHandleFunc(path, handlerFunc, methods)
    
package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/GuilhermeCaruso/bellt"
)

func main() {
	router := bellt.NewRouter()

	router.HandleGroup("/api",
		router.SubHandleFunc("/bellt", belltHandle, "GET"),
		router.SubHandleFunc("/check", checkHandle, "GET"),
	)

	log.Fatal(http.ListenAndServe(":8080", nil))
}

func belltHandle(w http.ResponseWriter, r *http.Request){
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("Simple Golang HTTP router")
}

func checkHandle(w http.ResponseWriter, r *http.Request){
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("Ok!")
}

Middleware

The declaration of middlewares in HandleFunc or SubHandleFunc should be done using the Use method

Use
/*
	handlerFunc - Function that will be called on the request 
	middlewareList - Slice of middleware that will be used in the request (Middleware)
*/
bellt.Use(handlerFunc, ...middlewareList)

The middleware type has a following signature

type Middleware func(http.HandlerFunc) http.HandlerFunc

Applying middlewares to routes

package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/GuilhermeCaruso/bellt"
)

func main() {

	router := bellt.NewRouter()

	router.HandleFunc("/hello", bellt.Use(
		exampleHandler,
		middlewareOne,
		middlewareTwo,
	), "GET")

	router.HandleGroup("/api",
		router.SubHandleFunc("/hello", bellt.Use(
			exampleHandler,
			middlewareOne,
			middlewareTwo,
		), "GET"),
	)

	log.Fatal(http.ListenAndServe(":8080", nil))
}

func exampleHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(`Hello Middleware!`))
}

func middlewareOne(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("Step One")
		next.ServeHTTP(w, r)
	}
}

func middlewareTwo(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("Step Two")
		next.ServeHTTP(w, r)
	}
}

Parameterized Routes

Route parameters must be passed using {} as scope limiter

router.HandleFunc("/hello/{name}", handlerFunc, "GET")

router.HandleGroup("/api", 
	SubHandleFunc("/item/{id}", handlerFunc, "GET")
)
Route Variables

RouteVariables used to capture and store parameters passed to built routes.

Need to pass the *Request of the HandlerFunc used in the HandleFunc method.

/*
	r = *Request of the HandlerFunc
*/
rv := bellt.RouteVariables(r)

The declaration must be made within the HandlerFunc

func exampleHandler(w http.ResponseWriter, r *http.Request) {
	rv := bellt.RouteVariables(r)
	/*[...]*/
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("Hello!"))
}
GetVar

GetVar returns the parameter value of the route

/*
	r = *Request of the HandlerFunc
	param = Parameter name string
*/
rv := bellt.RouteVariables(r)

rv.GetVar(param)
func exampleHandler(w http.ResponseWriter, r *http.Request) {
	rv := bellt.RouteVariables(r)
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(fmt.Sprintf(`Hello %v gopher!`, rv.GetVar("color")))))
}

The complete implementation of parameterized routes should look like this:

package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/GuilhermeCaruso/bellt"
)

func main() {

	router := bellt.NewRouter()

	router.HandleFunc("/contact/{id}/{user}", exampleHandler, "GET")

	router.HandleGroup("/api",
		router.SubHandleFunc("/check/{id}/{user}", exampleHandler, "GET"),
	)

	log.Fatal(http.ListenAndServe(":8080", nil))
}

func exampleHandler(w http.ResponseWriter, r *http.Request) {
	rv := bellt.RouteVariables(r)

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(fmt.Sprintf(`{"id": %v, "user": %v}`, rv.GetVar("user"), rv.GetVar("id"))))
}

Full Example

package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/GuilhermeCaruso/bellt"
)

func main() {

	router := bellt.NewRouter()

	router.HandleFunc("/contact/{id}/{user}", bellt.Use(
		exampleHandler,
		middlewareOne,
		middlewareTwo,
	), "GET")

	router.HandleFunc("/contact", bellt.Use(
		exampleNewHandler,
		middlewareOne,
		middlewareTwo,
	), "GET")

	router.HandleGroup("/api",
		router.SubHandleFunc("/check", bellt.Use(
			exampleNewHandler,
			middlewareOne,
			middlewareTwo,
		), "GET"),
		router.SubHandleFunc("/check/{id}/{user}", bellt.Use(
			exampleHandler,
			middlewareOne,
			middlewareTwo,
		), "GET"),
	)

	log.Fatal(http.ListenAndServe(":8080", nil))
}

func exampleHandler(w http.ResponseWriter, r *http.Request) {

	rv := bellt.RouteVariables(r)

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(fmt.Sprintf(`{"id": %v, "user": %v}`, rv.GetVar("user"), rv.GetVar("id"))))
}

func exampleNewHandler(w http.ResponseWriter, r *http.Request) {
	rv := bellt.RouteVariables(r)

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(`{"msg": "Works"}`))
}

func middlewareOne(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("Step One")

		next.ServeHTTP(w, r)
	}
}

func middlewareTwo(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("Step Two")

		next.ServeHTTP(w, r)
	}
}

Benchmark

Applying requisition performance tests, the following results were obtained, showing the initial potency of the Bellt package.

Author

Guilherme Caruso @guicaruso_ on twitter

Presentation

Guilherme Caruso - Cabify- GolangSP Meetup 2 - 21/03/2019 - São Paulo /Brazil

Slides - Construindo Rotas Parametrizadas em GO

Video - GolangSP Meetup 2

License

MIT licensed. See the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Use

func Use(handler http.HandlerFunc, middleware ...Middleware) http.HandlerFunc

Use becomes responsible for executing all middlewares passed through a cascade method.

Types

type BuiltRoute

type BuiltRoute struct {
	TempPath string
	Handler  http.HandlerFunc
	Var      map[int]Variable
	KeyRoute string
	Methods  []string
}

BuiltRoute is an internal pattern struct for routes that will be built at run time.

type Middleware

type Middleware func(http.HandlerFunc) http.HandlerFunc

Middleware is a type responsible for characterizing middleware functions that should be used in conjunction with bellt.Use().

type ParamReceiver

type ParamReceiver struct {
	// contains filtered or unexported fields
}

ParamReceiver is responsible to return params set on context

func RouteVariables

func RouteVariables(r *http.Request) *ParamReceiver

RouteVariables used to capture and store parameters passed to built routes

func (*ParamReceiver) GetVar

func (pr *ParamReceiver) GetVar(variable string) interface{}

GetVar return a value of router variable

type Route

type Route struct {
	Path    string
	Handler http.HandlerFunc
	Params  []Variable
}

Route is a struct responsible for storing basic information of a Route, with all its variable parameters recorded.

type Router

type Router struct {
	// contains filtered or unexported fields
}

Router is a struct responsible for storing routes already available (Route) or routes that will still be available (BuiltRoute).

func NewRouter

func NewRouter() *Router

NewRouter is responsible to initialize a "singleton" router instance.

func (*Router) HandleFunc

func (r *Router) HandleFunc(path string, handleFunc http.HandlerFunc, methods ...string)

HandleFunc function responsible for initializing a common route or built through the Router. All non-grouped routes must be initialized by this method.

func (*Router) HandleGroup

func (r *Router) HandleGroup(mainPath string, sr ...*SubHandle)

HandleGroup used to create and define a group of sub-routes

func (*Router) SubHandleFunc

func (r *Router) SubHandleFunc(path string, handleFunc http.HandlerFunc,
	methods ...string) *SubHandle

SubHandleFunc is responsible for initializing a common or built route. Its use must be made within the scope of the HandleGroup() method, where the main path will be declared.

type SubHandle

type SubHandle struct {
	Path    string
	Handler http.HandlerFunc
	Methods []string
}

SubHandle is a struct similar to Route, however its behavior must be related to GroupHandle, having all its behavior mirrored from a Route.

type Variable

type Variable struct {
	Name  string
	Value string
}

Variable is a struct that guarantees the correct mapping of variables used in built routes.

Source Files

Directories

Path Synopsis
pkg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL