nanny

package module
v1.0.0-beta.10 Latest Latest
Warning

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

Go to latest
Published: Nov 8, 2020 License: MIT Imports: 20 Imported by: 0

README

nanny

Build codecov Go Report Card

A web framework for Go with simple APIs to use. It solves common problems of a web server so engineers can focus on business logic.

Features

  • Graceful shutdown
  • Panic recovery
  • CORS
  • Gzip compression
  • Dependency injection

Quick Start

Installation

Make sure Go (version 1.13+ is required) is installed.

go get github.com/bongnv/nanny
Example
package main

import (
	"context"
	"log"

	"github.com/bongnv/nanny"
)

func main() {
    app := nanny.Default()
    app.GET("/hello-world", func(ctx context.Context, req nanny.Request) (interface{}, error) {
        return "OK", nil
    })
    log.Println(app.Run())
}

Usages

Options

An Option customizes an Application and these are available Option:

WithLogger

WithLogger allows to specify a custom implementation of the logger.

  logger := log.New(os.Stderr, "", log.LstdFlags)
  app := nanny.New(nanny.WithLogger(logger))
WithPProf

WithPProf starts another HTTP service in a different port to serve endpoints for pprof. The option is included in the default app with port 8081.

  app := nanny.New(WithPProf(":8081"))
Route Options

A RouteOption customizes a route. It can be used to add middlewares like Recovery().

For convenience, a RouteOption can be a Option for the Application. In this case, the RouteOption will be applied to all routes.

WithRecovery

WithRecovery recovers from panics and returns error with 500 status code to clients.

    app.GET("/hello-world", helloWorld, nanny.WithRecovery())
WithDecoder

WithDecoder specifies a custom logic for decoding the request to a request DTO.

   app.GET("/hello-world", helloWorld, nanny.WithDecoder(customDecoder))
WithCORS

WithCORS enables the support for Cross-Origin Resource Sharing. Ref: https://developer.mozilla.org/en/docs/Web/HTTP/Access_control_CORS.

  app := nanny.New(nanny.WithCORS(nanny.DefaultCORSConfig))
  // or
  app.GET("/hello-world", helloWorld, nanny.WithCORS(nanny.DefaultCORSConfig))
WithTimeout

WithTimeout allows to specify the time limit for each route. 1 second timeout is included in the default app.

  app.GET("/hello-world", helloWorld, nanny.WithTimeout(time.Second)
WithErrorHandler

WithErrorHandler allows to specify a custom ErrorHandler which converts an error into HTTP response.

func yourCustomErrHandler(w http.ResponseWriter, errResp error) error {
    w.WriteHeader(http.StatusInternalServerError)
    if err := encoder.Encode(w, errResp); err != nil {
        logger.Println("Error", err, "while encoding", errResp)
        return err
    }

    return nil
}

func yourInitFunc(app *nanny.Application) {
    app.GET("/hello-world", helloWorld, nanny.WithErrorHandler(yourCustomErrHandler))
}
Grouping routes

nanny supports grouping routes which share the same prefix or options for better readability.

func main() {
    app := nanny.Default()

    // v1 group
    v1 := app.Group("/v1", WithV1Option())
    v1.GET("/hello-world", helloWorldV1)

    // v2 group
    v2 := app.Group("/v2", WithV2Option())
    v2.GET("/hello-world", helloWorldV2)

    log.Println(app.Run())
}
Dependency injection

nanny makes dependency injection much easier by Register.

// Service declares dependencies via `inject` tag.
type Service struct {
    DB *db.DB `inject:"db"` 
    Logger *Logger `inject:"logger"`
}

func main() {
    // Logger is provided with default implementation.
    app := nanny.Default()
    // Register DB component.
    app.Register("db", newDB())

    s := &Service{}
    // Logger and DB will be injected when registering service.
    app.Register("service", s)
}

Documentation

Index

Constants

View Source
const (
	HeaderAcceptEncoding                = "Accept-Encoding"
	HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
	HeaderAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
	HeaderAccessControlAllowMethods     = "Access-Control-Allow-Methods"
	HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
	HeaderAccessControlMaxAge           = "Access-Control-Max-Age"
	HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
	HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
	HeaderContentEncoding               = "Content-Encoding"
	HeaderContentLength                 = "Content-Length"
	HeaderContentType                   = "Content-Type"
	HeaderOrigin                        = "Origin"
	HeaderVary                          = "Vary"
)

Headers

Variables

View Source
var DefaultCORSConfig = CORSConfig{
	AllowOrigins: []string{"*"},
	AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},
}

DefaultCORSConfig is the default configuration for the WithCORS middleware.

View Source
var (
	// DefaultGzipConfig is the default config for Gzip middleware.
	DefaultGzipConfig = GzipConfig{
		Level: gzip.DefaultCompression,
	}
)

Functions

func ResponseHeaderFromCtx

func ResponseHeaderFromCtx(ctx context.Context) http.Header

ResponseHeaderFromCtx returns Header for HTTP response which will be sent. The function returns a nil map if the Header doesn't exist.

Types

type Application

type Application struct {
	*RouteGroup
	// contains filtered or unexported fields
}

Application is a web application.

func Default

func Default(opts ...Option) *Application

Default returns an Application with a default set of configurations.

func New

func New(opts ...Option) *Application

New creates a new application.

func (*Application) Component

func (app *Application) Component(name string) (interface{}, error)

Component finds and returns a component via name. It returns an error if the requested component couldn't be found.

func (*Application) MustComponent

func (app *Application) MustComponent(name string) interface{}

MustComponent finds and returns a component via name. It panics if there is any error.

func (*Application) MustRegister

func (app *Application) MustRegister(name string, component interface{})

MustRegister registers a new component to the application. It panics if there is any error.

func (*Application) Register

func (app *Application) Register(name string, component interface{}) error

Register registers a new component to the application.

func (*Application) Run

func (app *Application) Run()

Run starts an HTTP server.

type CORSConfig

type CORSConfig struct {
	AllowOrigins     []string
	AllowMethods     []string
	AllowHeaders     []string
	AllowCredentials bool
	MaxAge           int
}

CORSConfig defines the config for WithCORS middleware.

type CustomHTTPResponse

type CustomHTTPResponse interface {
	WriteTo(w http.ResponseWriter)
}

CustomHTTPResponse defines an interface to support custom HTTP response.

type Decoder

type Decoder interface {
	// Decode decodes a request to a struct. req.PostForm is called in advanced.
	Decode(obj interface{}, req *http.Request) error
}

Decoder defines a request decoder.

type Encoder

type Encoder interface {
	// Encode encodes obj and writes to http.ResponseWriter.
	Encode(w http.ResponseWriter, resp interface{}) error
}

Encoder define a request decoder.

type ErrorHandler

type ErrorHandler func(w http.ResponseWriter, err error) error

ErrorHandler defines a handler which handles error.

type GzipConfig

type GzipConfig struct {
	// Gzip compression level.
	// Optional. Default value -1.
	Level int
}

GzipConfig defines the config for Gzip middleware.

type HTTPError

type HTTPError struct {
	Code    int    `json:"-"`
	Message string `json:"message"`
}

HTTPError is a simple implementation of HTTP Error.

func (HTTPError) Error

func (err HTTPError) Error() string

Error implements error interface.

func (HTTPError) WriteTo

func (err HTTPError) WriteTo(w http.ResponseWriter)

WriteTo implements CustomHTTPResponse. It encodes the response as JSON format.

type Handler

type Handler func(ctx context.Context, req Request) (interface{}, error)

Handler defines a function to serve HTTP requests.

type Logger

type Logger interface {
	// Println prints out logs like fmt.Println.
	Println(...interface{})
}

Logger defines a Logger.

type Middleware

type Middleware func(Handler) Handler

Middleware defines a middleware to provide additional logic.

func WithCORS

func WithCORS(cfg CORSConfig) Middleware

WithCORS returns a middleware to support Cross-Origin Resource Sharing.

func (Middleware) Apply

func (m Middleware) Apply(app *Application)

Apply implements Option.

func (Middleware) ApplyRoute

func (m Middleware) ApplyRoute(r *route)

ApplyRoute implements RouteOption.

type Option

type Option interface {
	Apply(app *Application)
}

Option defines an application Option.

type OptionFn

type OptionFn func(app *Application)

OptionFn defines a function that implements Option

func WithAddress

func WithAddress(addr string) OptionFn

WithAddress specifies the TCP address for the server to listen on,

func WithLogger

func WithLogger(l Logger) OptionFn

WithLogger specifies a custom Logger for tha application.

func WithPProf

func WithPProf(addr string) OptionFn

WithPProf enables the pprof server.

func (OptionFn) Apply

func (opt OptionFn) Apply(app *Application)

Apply implements Option.

type Plugin

type Plugin []Option

Plugin is a set of Option to enrich an application.

var DefaultApp Plugin = []Option{
	WithLogger(defaultLogger()),
	WithRecovery(),
	WithCORS(DefaultCORSConfig),
	WithGzip(DefaultGzipConfig),
	WithTimeout(1 * time.Second),
	WithPProf(":8081"),
}

DefaultApp is a plugin to provide a set of common options for an application.

func (Plugin) Apply

func (p Plugin) Apply(app *Application)

Apply implements Option interface. It applies options to the application.

type Request

type Request interface {
	// HTTPRequest returns the http.Request.
	HTTPRequest() *http.Request
	// Decode decodes the request to an object.
	Decode(obj interface{}) error
}

Request defines a HTTP request.

type RouteGroup

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

RouteGroup is a group of sub-routes. It can be used for a group of routes which share same middlewares.

func (*RouteGroup) DELETE

func (g *RouteGroup) DELETE(path string, h Handler, opts ...RouteOption)

DELETE registers a new DELETE route for a path with handler.

func (*RouteGroup) GET

func (g *RouteGroup) GET(path string, h Handler, opts ...RouteOption)

GET registers a new GET route for a path with handler.

func (*RouteGroup) Group

func (g *RouteGroup) Group(prefix string, opts ...RouteOption) *RouteGroup

Group creates a group of sub-routes

func (*RouteGroup) PATCH

func (g *RouteGroup) PATCH(path string, h Handler, opts ...RouteOption)

PATCH registers a new PATCH route for a path with handler.

func (*RouteGroup) POST

func (g *RouteGroup) POST(path string, h Handler, opts ...RouteOption)

POST registers a new POST route for a path with handler.

func (*RouteGroup) PUT

func (g *RouteGroup) PUT(path string, h Handler, opts ...RouteOption)

PUT registers a new PUT route for a path with handler.

type RouteOption

type RouteOption interface {
	ApplyRoute(r *route)
}

RouteOption defines an option to customize a route.

type RouteOptionFn

type RouteOptionFn func(r *route)

RouteOptionFn defines a function implementation of RouteOption.

func WithDecoder

func WithDecoder(d Decoder) RouteOptionFn

WithDecoder specifies the decoder which will be used.

func WithEncoder

func WithEncoder(e Encoder) RouteOptionFn

WithEncoder specifies the encoder which will be used to encode payload to HTTP response.

func WithErrorHandler

func WithErrorHandler(errHandler ErrorHandler) RouteOptionFn

WithErrorHandler is a RouteOption to specify a custom ErrorHandler.

func WithGzip

func WithGzip(cfg GzipConfig) RouteOptionFn

WithGzip returns a middleware which compresses HTTP response using gzip compression.

func WithRecovery

func WithRecovery() RouteOptionFn

WithRecovery returns a middleware which recovers from panics.

func WithTimeout

func WithTimeout(timeout time.Duration) RouteOptionFn

WithTimeout specifies the time limit for a route.

func (RouteOptionFn) Apply

func (fn RouteOptionFn) Apply(app *Application)

Apply implements Option.

func (RouteOptionFn) ApplyRoute

func (fn RouteOptionFn) ApplyRoute(r *route)

ApplyRoute implements RouteOption.

Directories

Path Synopsis
db
examples

Jump to

Keyboard shortcuts

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