http

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: May 6, 2019 License: MIT Imports: 17 Imported by: 0

README

CircleCI codecov GoDoc Go Report Card

HTTP

This is one more web development framework for GO using the fasthttp as base. Or, maybe, it is just a set of utility of helpful functions that apply some sugar to the fasthttp "daily" usage.

Extra Features

Routing

Routable is described as an interface which have the Delete, Get, Head, Options, Patch, Post, Put methods for routing. This aims to replace the fasthttprouter implementation.

In order to get things going, the below example shows how to define an endpoint serving a GET method:

router := http.DefaultRouter()

router.Get("/api/v1/user", func(req http.Request, res http.Response) http.Result {
	res.Data("the user is: Snake Eyes")
})
Grouping

When dealing with routes, groups are awesome!

router := http.DefaultRouter()

apiGroup := router.Prefix("/api") // This retuns a `Routable` that can be used
                                  // to create other subgroups or define routes.

apiv1 := apiGroup.Prefix("/v1")   // This is what we define as a subgroup.
apiv1.Get(                        // Now a definition of the route itself.
	"/user",
	func(req http.Request, res http.Response) http.Result {
		return res.Data("the user is: Snake Eyes")
	},
)
// many other routes using `apiv1` ...

There is no difference from using, or not, grouping into the routes definition. Internally, the implementation ends up joining all the routes of the group with the group prefix. Hence, groups will not affect performance.

Middlewares

In order to provide a more flexible API, Middleware supports were added.

Middlewares can implement some verification or extension logic and decide whether or not continue to run the "next" middleware/handler.

router := http.DefaultRouter()

apiGroup := router.Prefix("/api")

apiv1 := apiGroup.Prefix("/v1")

apiv1.Use(func(req http.Request, res http.Response, next http.Handler) http.Result {
	// This is a middleware that could do something smart...
	return next(req, res)
})

apiv1.Get(
	"/user",
	func(req http.Request, res http.Response) http.Result {
		return res.Data("the user is: Snake Eyes")
	},
)

Yet, you can also define multiple middlewares for each route and their priority will be from the left to the right.

router := http.DefaultRouter()

apiGroup := router.Prefix("/api")
apiv1 := apiGroup.Prefix("/v1")
apiv1.With(
	func(req http.Request, res http.Response, next http.Handler) http.Result {
		// This is a middleware that could do something smart...
		return next(ctx)
	},
	func(req http.Request, res http.Response, next http.Handler) http.Result {
		// This is a second middleware for the endpoint...
		return next(ctx)
	},
).Get(
	"/user",
	func(req http.Request, res http.Response) http.Result {
		return res.Data("the user is: Snake Eyes")
	},
)

Middlewares are also supported on groups:

router := http.DefaultRouter()

apiGroup := router.Prefix("/api").With(func(req http.Request, res http.Resonse, next http.Handler) http.Result {
	// This is a middleware that could do something smart...
	return next(ctx)
})
apiv1 := apiGroup.Prefix("/v1").With(func(req http.Request, res http.Resonse, next http.Handler) http.Result {
	// Yet another middleware applied just for this subgroup...
	return next(ctx)
})
apiv1.With(func(req http.Request, res http.Resonse, next http.Handler) http.Result {
	// This is a middleware that is applied just for this endpoint
	return next(ctx)
}).Get(
	"/user",
	func(req http.Request, res http.Resonse) http.Result {
		return res.Data("the user is: Snake Eyes")
	},
)

Again, there is no performance difference when using middlewares in a specific route or in a whole group. The internal implementation will append both middleware definitions into one big sequence of middlewares for each route.

Thin JSON layer

For simple sake of ease the use of sending and receiving JSON objects res.Data and req.Data methods were added.

Sending a JSON

The following is an example of sending a JSON document:

router := http.DefaultRouter()

apiv1 := router.Prefix("/api/v1")
apiv1.Get(
	"/user",
	func(req http.Request, res http.Response) http.Result {
		return res.Data(map[string]interface{}{
			"name": "Snake Eyes",
			"email": "s.eyes@gijoe.com",
		})
	},
)
Receiving a JSON

The following is an example of receiving a JSON document:

router := http.DefaultRouter()

apiv1 := router.Group("/api/v1")
apiv1.Post(
	"/user",
	func(req http.Request, res http.Response) http.Result {
		user := make(map[string]interface{})
		if err := req.Data(&user); err != nil {
			return res.Status(400).Data(map[string]interface{}{
				"error": "user data invalid"
			})
		}
		// To process the user information
	},
)

fasthttprouter

buaazp/fasthttprouter forks julienschmidt/httprouter adding support for the valyala/fasthttp.

The implementation is very efficient. However, sometimes we could not find a way to place our routes the exact way we wanted to. In order to solve this problem, we implemented our own version (unfortunately less effective).

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	InternalServerErrorCode    = "internal-server-error"
	InternalServerErrorMessage = "We encountered an internal error or misconfiguration and was unable to complete your request."

	NotFoundErrorCode    = "not-found"
	NotFoundErrorMessage = "We could not find the resource you requested."

	MethodNotAllowedErrorCode    = "method-not-allowed"
	MethodNotAllowedErrorMessage = "We believe that the used request method is inappropriate for the resource you requested."
)
View Source
var (
	ErrWrongConfigurationInformed = errors.New("wrong configuration informed")
	ErrServiceNotRunning          = errors.New("service not running")
)

Functions

This section is empty.

Types

type Application added in v1.0.0

type Application struct {
	Configuration ApplicationConfig
	// contains filtered or unexported fields
}

func NewApplication added in v1.0.0

func NewApplication(config ApplicationConfig, router Router) *Application

func (*Application) ApplyConfiguration added in v1.0.0

func (app *Application) ApplyConfiguration(interface{}) error

func (*Application) LoadConfiguration added in v1.0.0

func (app *Application) LoadConfiguration() (interface{}, error)

func (*Application) Name added in v1.0.0

func (app *Application) Name() string

func (*Application) Restart added in v1.0.0

func (app *Application) Restart() error

func (*Application) Start added in v1.0.0

func (app *Application) Start() error

func (*Application) Stop added in v1.0.0

func (app *Application) Stop() error

type ApplicationConfig added in v1.0.0

type ApplicationConfig struct {
	Name string
	HTTP FasthttpServiceConfiguration
}

type ColorServiceReporter

type ColorServiceReporter struct{}

func (*ColorServiceReporter) AfterApplyConfiguration

func (*ColorServiceReporter) AfterApplyConfiguration(service Service, conf interface{}, err error)

func (*ColorServiceReporter) AfterLoadConfiguration

func (*ColorServiceReporter) AfterLoadConfiguration(service Service, conf interface{}, err error)

func (*ColorServiceReporter) AfterStart

func (*ColorServiceReporter) AfterStart(service Service, err error)

func (*ColorServiceReporter) BeforeApplyConfiguration

func (*ColorServiceReporter) BeforeApplyConfiguration(service Service)

func (*ColorServiceReporter) BeforeBegin

func (*ColorServiceReporter) BeforeBegin(service Service)

func (*ColorServiceReporter) BeforeLoadConfiguration

func (*ColorServiceReporter) BeforeLoadConfiguration(service Service)

func (*ColorServiceReporter) BeforeStart

func (*ColorServiceReporter) BeforeStart(service Service)

type ConfigurationLoader

type ConfigurationLoader interface {
	// Load receives the `id` of the configuration and Unmarshals it
	// int the `dst` pointer. If no error is reported the method will
	// return nil otherwise the error will be returned.
	Load(id string) ([]byte, error)
}

ConfigurationLoader defines the contract to load a configuration from a repository.

The repository is an abstract idea that can be represented as a directory, a S3 bucket, or "anything" else.

type ConfigurationUnmarshaler

type ConfigurationUnmarshaler interface {
	Unmarshal(buf []byte, dst interface{}) error
}

ConfigurationUnmarshaler describes the unmarshaling contract of a configuration.

type ConfigurationUnmarshalerYaml

type ConfigurationUnmarshalerYaml struct {
}
var DefaultConfigurationUnmarshalerYaml ConfigurationUnmarshalerYaml

func (*ConfigurationUnmarshalerYaml) Unmarshal

func (loader *ConfigurationUnmarshalerYaml) Unmarshal(buff []byte, dst interface{}) error

Unmarshal is an abstract method that should be override

type ConfigurationUnmarshelerJson

type ConfigurationUnmarshelerJson struct {
}
var DefaultConfigurationUnmarshalerJson ConfigurationUnmarshelerJson

func (*ConfigurationUnmarshelerJson) Unmarshal

func (loader *ConfigurationUnmarshelerJson) Unmarshal(buff []byte, dst interface{}) error

Unmarshal is an abstract method that should be override

type FasthttpService

type FasthttpService struct {
	Configuration FasthttpServiceConfiguration
	Listener      net.Listener
	Server        fasthttp.Server
	// contains filtered or unexported fields
}

FasthttpService implements the server for starting

func (*FasthttpService) ApplyConfiguration

func (service *FasthttpService) ApplyConfiguration(configuration interface{}) error

ApplyConfiguration checks if the passing interface is a `FasthttpServiceConfiguration` and applies its configuration to the service.

func (*FasthttpService) LoadConfiguration

func (service *FasthttpService) LoadConfiguration() (interface{}, error)

LoadConfiguration does not do anything in this implementation. This methods is just a placeholder to be overwritten on its usage.

func (*FasthttpService) Restart

func (service *FasthttpService) Restart() error

Reload returns an error due to fasthttp not being able to stop the service.

func (*FasthttpService) Start

func (service *FasthttpService) Start() error

Start ListenAndServe the server. This method is blocking because it uses the fasthttp.ListenAndServe implementation.

func (*FasthttpService) Stop

func (service *FasthttpService) Stop() error

Stop closes the listener and waits the `Start` to stop.

type FasthttpServiceConfiguration

type FasthttpServiceConfiguration struct {
	Bind string
}

FasthttpServiceConfiguration keeps all the configuration needed to start the `FasthttpService`.

type FileConfigurationLoader

type FileConfigurationLoader struct {
	Directory string
}

func NewFileConfigurationLoader

func NewFileConfigurationLoader(dir string) *FileConfigurationLoader

func (*FileConfigurationLoader) Load

func (loader *FileConfigurationLoader) Load(id string) ([]byte, error)

type Handler

type Handler func(req Request, res Response) Result

type Middleware

type Middleware func(req Request, res Response, next Handler) Result

Middleware is an interface for adding middleware to a Router instance

type NopServiceReporter

type NopServiceReporter struct{}

func (*NopServiceReporter) AfterApplyConfiguration

func (*NopServiceReporter) AfterApplyConfiguration(service Service, conf interface{}, err error)

func (*NopServiceReporter) AfterLoadConfiguration

func (*NopServiceReporter) AfterLoadConfiguration(service Service, conf interface{}, err error)

func (*NopServiceReporter) AfterStart

func (*NopServiceReporter) AfterStart(service Service, err error)

func (*NopServiceReporter) BeforeApplyConfiguration

func (*NopServiceReporter) BeforeApplyConfiguration(service Service)

func (*NopServiceReporter) BeforeBegin

func (*NopServiceReporter) BeforeBegin(service Service)

func (*NopServiceReporter) BeforeLoadConfiguration

func (*NopServiceReporter) BeforeLoadConfiguration(service Service)

func (*NopServiceReporter) BeforeStart

func (*NopServiceReporter) BeforeStart(service Service)

type Request added in v1.0.0

type Request interface {
	// Path returns the path of the current URL
	Path() []byte

	// Method returns the HTTP method
	Method() []byte

	// IsJSON return weather request body is application/json
	IsJSON() bool

	// WantsJSON return weather request accepts application/json
	WantsJSON() bool

	// URI returns the raw URI
	URI() *fasthttp.URI

	// Header return a header value by name. If the header is not found
	// an empty string will be returned.
	Header(name string) []byte

	// Host returns the host of the request.
	Host() []byte

	// Param grabs route param by name
	Param(name string) string

	// Query grabs input from the query string by name
	Query(name string) []byte

	// QueryMulti grabs multiple input from the query string by name
	QueryMulti(name string) [][]byte

	// Data unmarshals request body to dst
	Data(dst interface{}) error

	// Post grabs input from the post data by name
	Post(name string) []byte

	// PostMulti grabs multiple input from the post data by name
	PostMulti(name string) [][]byte

	// Cookie grabs input from cookies by name
	Cookie(name string) []byte

	// Context returns the context.Context of the current request
	Context() context.Context

	// WithContext returns a shallow copy of the request with a new context
	WithContext(ctx context.Context) Request

	// Raw returns the fasthttp.RequestCtx of the current request
	Raw() *fasthttp.RequestCtx
}

Request is used to retrieve data from an HTTP request

type Response added in v1.0.0

type Response interface {
	// Cookie sets an HTTP cookie on the response
	// See also `fasthttp.AcquireCookie`
	Cookie(cookie *fasthttp.Cookie) Response

	// Status sets the HTTP status code of the response. This can only be called once.
	Status(status int) Response

	// Header adds an HTTP header to the response
	Header(name, value string) Response

	// Data responds with data provided
	//
	// Most types will converted to a string representation except structs,
	// arrays and maps which will be serialized to JSON.
	Data(data interface{}) Result

	// Error sends the default 500 response
	Error(error) Result

	File(filepath string) Result

	FileDownload(filepath, filename string) Result

	// Redirect redirects the client to a URL
	Redirect(uri string, code int) Result

	// End ends the response chain
	End() Result
}

Response is used to send data to the client

type Result added in v1.0.0

type Result interface {
	Data(data interface{}) Result
	Error(error) Result
	Redirect(uri string, code int) Result
	File(filepath string) Result
	FileDownload(filepath, filename string) Result
	// End release the resources
	End()
}

Result is used to finish a request

type Routable

type Routable interface {
	Delete(path string, handler Handler)
	Get(path string, handler Handler)
	Head(path string, handler Handler)
	Options(path string, handler Handler)
	Patch(path string, handler Handler)
	Post(path string, handler Handler)
	Put(path string, handler Handler)

	Prefix(path string) Routable
	Group(func(Routable))

	Use(...Middleware)
	With(...Middleware) Routable
}

type Router

type Router interface {
	Routable

	Handler() fasthttp.RequestHandler
}

func DefaultRouter added in v1.0.0

func DefaultRouter() Router

func NewRouter

func NewRouter(config RouterConfig) Router

type RouterConfig added in v1.0.0

type RouterConfig struct {
	NotFound         Handler
	MethodNotAllowed Handler
}

type Service

type Service interface {
	// Name identifies the service.
	Name() string

	// Loads the configuration. If successful nil will be returned, otherwise
	// the error.
	LoadConfiguration() (interface{}, error)

	// Applies a given configuration object to the service. If successful nil
	// will be returned, otherwise the error.
	ApplyConfiguration(interface{}) error

	// Restarts the service. If successful nil will be returned, otherwise the
	// error.
	Restart() error

	// Start starts the service. If successful nil will be returned, otherwise
	// the error.
	Start() error

	// Stop stops the service. If successful nil will be returned, otherwise the
	// error.
	Stop() error
}

Service is an abstraction for implementing parts that can be loaded, reloaded, started and stopped inside of the system.

Maybe you can implement your HTTP service like this, or your Redis resource. As simple and wide as it could be this directive will provide an defined signature to implement all your resources.

type ServiceStarter

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

func NewServiceStarter

func NewServiceStarter(services []Service, reporter ServiceStarterReporter) *ServiceStarter

func (*ServiceStarter) Start

func (engineStarter *ServiceStarter) Start() error

type ServiceStarterReporter

type ServiceStarterReporter interface {
	BeforeBegin(service Service)

	BeforeLoadConfiguration(service Service)
	AfterLoadConfiguration(service Service, conf interface{}, err error)

	BeforeApplyConfiguration(service Service)
	AfterApplyConfiguration(service Service, conf interface{}, err error)

	BeforeStart(service Service)
	AfterStart(service Service, err error)
}

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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