servicefoundation

package module
v0.0.0-...-3413596 Latest Latest
Warning

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

Go to latest
Published: Sep 13, 2017 License: MIT Imports: 18 Imported by: 0

README

ServiceFoundation Build Status

Go Report Card Coverage Status license

Create new Web Services using convention-based configuration.

More documentation to be found on GodDoc.

ServiceFoundation enables you to create Web Services containing:

  • 3 access levels (public, readiness and internal)
  • Customizable logging (defaults to go-logger)
  • Customizable metrics collection (defaults to go-metrics)
  • Out-of-the-box middleware for panic handling, no-cache, counters, histograms and CORS.
  • Default and overridable handling of catch-all (root), liveness, health, version and readiness
  • Handling of SIGTERM and SIGINT with a custom shutdown function to properly free your own resources.
  • Customizable server timeouts
  • Request/response logging as middleware
  • Support service warm-up through state customization

To do:

  • Standardize metrics
  • Standardize log messages
  • Extend logging with meta information
  • De-duplicate CORS elements in slices
  • Automated documentation (GoDocs?)

Package usage

Include this package into your project with:

go get github.com/Prutswonder/go-servicefoundation

Although all components can be extended, the easiest way to use ServiceFoundation is to use the boilerplate version:

package main

import (
	"context"
	"net/http"

	sf "github.com/Prutswonder/go-servicefoundation"
)

func main() {
	svc := sf.NewService("HelloWorldService", []string{http.MethodGet},
		func(log sf.Logger) {
			log.Info("GracefulShutdown", "Handling graceful shutdown")
		})

	svc.AddRoute("helloworld", []string{"/helloworld"}, sf.MethodsForGet, sf.DefaultMiddlewares,
		func(w sf.WrappedResponseWriter, _ *http.Request, _ sf.RouterParams) {
			w.JSON(http.StatusOK, "hello world!")
		})

	svc.Run(context.Background()) // blocks execution
}

The following environment variables are used by ServiceFoundation:

Name Used for
CORS_ORIGINS Comma-separated list of CORS origins (default:*)
HTTPPORT Port used for exposing the public endpoint (default: 8080)
LOG_MINFILTER Minimum filter for log writing (default: Warning)
APP_NAME Name of the application (HelloWorldService)
SERVER_NAME Name of the server instance (helloworldservice-1234)
DEPLOY_ENVIRONMENT Name of the deployment environment (default: staging)
GO_PIPELINE_LABEL GOCD pipeline version number (default: ?)
BUILD_DATE Build date (default: ?)
GIT_HASH Git hash (default: ?)

Dependencies

Although ServiceFoundation contains interfaces to hide any external dependencies, the default configuration depends on the following packages:

Extending ServiceFoundation

You can use the servicefoundation.CreateService(ServiceOptions) method for extension. The provided ServiceOptions struct contains all the things you can extend. If you want to create your own ReadinessHandler, you can do so as follows:

package main

import (
	"context"
	"net/http"
	"time"

	sf "github.com/Prutswonder/go-servicefoundation"
)

type CustomServiceStateReader struct {
	sf.ServiceStateReader
	isWarmedUp bool
}

func (r *CustomServiceStateReader) IsLive() bool {
	return true
}

func (r *CustomServiceStateReader) IsReady() bool {
	return r.isWarmedUp
}

func (r *CustomServiceStateReader) IsHealthy() bool {
	return true
}

func main() {
	shutdownFn := func(log sf.Logger) {
		log.Info("GracefulShutdown", "Handling graceful shutdown")
	}

	stateReader := &CustomServiceStateReader{}

	go func() {
		// Simulating warm-up time...
		time.Sleep(10 * time.Second)
		stateReader.isWarmedUp = true
	}()

	opt := sf.NewServiceOptions("HelloWorldService", []string{http.MethodGet}, shutdownFn)
	opt.ServiceStateReader = stateReader
	opt.SetHandlers() // Required to re-bind the state to the ReadinessHandler

	svc := sf.NewCustomService(opt)

	svc.AddRoute("helloworld", []string{"/helloworld"}, sf.MethodsForGet, sf.DefaultMiddlewares,
		func(w sf.WrappedResponseWriter, _ *http.Request, _ sf.RouterParams) {
			w.JSON(http.StatusOK, "hello world!")
		})

	svc.Run(context.Background()) // blocks execution
}

license

Documentation

Index

Constants

View Source
const (
	// AcceptHeader is the name of the http Accept header.
	AcceptHeader = "Accept"
	// ContentTypeHeader is the name of the http content type header.
	ContentTypeHeader = "Content-Type"
	// ContentTypeJSON is the value of the http content type header for JSON documents.
	ContentTypeJSON = "application/json"
	// ContentTypeXML is the value of the http content type header for XML documents.
	ContentTypeXML = "application/xml"
)

Variables

View Source
var (
	// MethodsForGet contains a slice with the supported http methods for GET.
	MethodsForGet = []string{http.MethodGet}
	// MethodsForPost contains a slice with the supported http methods for POST.
	MethodsForPost = []string{http.MethodPost}
)
View Source
var DefaultMiddlewares = []Middleware{PanicTo500, RequestLogging, NoCaching}

DefaultMiddlewares contains the default middleware wrappers for the predefined service endpoints.

Functions

func NewExitFunc

func NewExitFunc(log Logger, shutdownFunc ShutdownFunc) func(int)

NewExitFunc returns a new exit function. It wraps the shutdownFunc and executed an os.exit after the shutdown is completed with a slight delay, giving the quit handler a chance to return a status.

Types

type BuildVersion

type BuildVersion struct {
	VersionNumber string `json:"version"`
	BuildDate     string `json:"buildDate"`
	GitHash       string `json:"gitHash"`
}

BuildVersion contains the version and build information of the application.

func NewBuildVersion

func NewBuildVersion() BuildVersion

NewBuildVersion creates and returns a new BuildVersion based on conventional environment variables.

type CORSOptions

type CORSOptions struct {
	// AllowedOrigins is a list of origins a cross-domain request can be executed from.
	// If the special "*" value is present in the list, all origins will be allowed.
	// An origin may contain a wildcard (*) to replace 0 or more characters
	// (i.e.: http://*.domain.com). Usage of wildcards implies a small performance penality.
	// Only one wildcard can be used per origin.
	// Default value is ["*"]
	AllowedOrigins []string
	// AllowedMethods is a list of methods the client is allowed to use with
	// cross-domain requests. Default value is simple methods (GET and POST)
	AllowedMethods []string
	// AllowedHeaders is list of non simple headers the client is allowed to use with
	// cross-domain requests.
	// If the special "*" value is present in the list, all headers will be allowed.
	// Default value is [] but "Origin" is always appended to the list.
	AllowedHeaders []string
	// ExposedHeaders indicates which headers are safe to expose to the API of a CORS
	// API specification
	ExposedHeaders []string
	// MaxAge indicates how long (in seconds) the results of a preflight request
	// can be cached
	MaxAge int
}

CORSOptions contains properties used for handling CORS requests.

type ExitFunc

type ExitFunc func(int)

ExitFunc is the function signature for the exit function used by Service.

type Handle

Handle is a function signature for the ServiceFoundation handlers

type Handlers

type Handlers struct {
	RootHandler      RootHandler
	ReadinessHandler ReadinessHandler
	LivenessHandler  LivenessHandler
	HealthHandler    HealthHandler
	VersionHandler   VersionHandler
	MetricsHandler   MetricsHandler
	QuitHandler      QuitHandler
}

Handlers is a struct containing references to handler implementations.

type HealthHandler

type HealthHandler interface {
	NewHealthHandler() Handle
}

HealthHandler is an interface to instantiate a new health handler.

type LivenessHandler

type LivenessHandler interface {
	NewLivenessHandler() Handle
}

LivenessHandler is an interface to instantiate a new liveness handler.

type Logger

type Logger interface {
	Debug(event, formatOrMsg string, a ...interface{}) error
	Info(event, formatOrMsg string, a ...interface{}) error
	Warn(event, formatOrMsg string, a ...interface{}) error
	Error(event, formatOrMsg string, a ...interface{}) error
	GetLogger() *logger.Logger
}

Logger is a wrapper around the Logger package and extending it with log level filtering and simplified formatting.

func NewLogger

func NewLogger(logMinFilter string) Logger

NewLogger instantiates a new Logger implementation.

type Metrics

type Metrics interface {
	Count(subsystem, name, help string)
	SetGauge(value float64, subsystem, name, help string)
	CountLabels(subsystem, name, help string, labels, values []string)
	IncreaseCounter(subsystem, name, help string, increment int)
	AddHistogram(subsystem, name, help string) MetricsHistogram
}

Metrics is a wrapper around the Metrics from the go-metrics package.

func NewMetrics

func NewMetrics(namespace string, logger Logger) Metrics

NewMetrics instantiates a new Metrics implementation.

type MetricsHandler

type MetricsHandler interface {
	NewMetricsHandler() Handle
}

MetricsHandler is an interface to instantiate a new metrics handler.

type MetricsHistogram

type MetricsHistogram interface {
	RecordTimeElapsed(start time.Time, unit time.Duration)
}

MetricsHistogram is a wrapper around the MetricsHistogram from the go-metrics package.

type Middleware

type Middleware int

Middleware is an enumeration to indicare the available middleware wrappers.

const (
	// CORS is a Middleware enumeration for validating cross-domain requests.
	CORS Middleware = 1
	// NoCaching is a middleware enumeration to adding no-caching headers to the response.
	NoCaching Middleware = 2
	// Counter is a middleware enumeration to add counter metrics to the current request/response.
	Counter Middleware = 3
	// Histogram is a middleware enumeration to add histogram metrics to the current request/response.
	Histogram Middleware = 4
	// PanicTo500 is a middleware enumeration to log panics as errors and respond with http status-code 500.
	PanicTo500 Middleware = 5
	// RequestLogging is a middleware enumeration to log the incoming request and response times.
	RequestLogging Middleware = 6
)

type MiddlewareWrapper

type MiddlewareWrapper interface {
	Wrap(subsystem, name string, middleware Middleware, handler Handle) Handle
}

MiddlewareWrapper is an interface to wrap an existing handler with the specified middleware.

func NewMiddlewareWrapper

func NewMiddlewareWrapper(logger Logger, metrics Metrics, corsOptions *CORSOptions, globals ServiceGlobals) MiddlewareWrapper

NewMiddlewareWrapper instantiates a new MiddelwareWrapper implementation.

type QuitHandler

type QuitHandler interface {
	NewQuitHandler() Handle
}

QuitHandler is an interface to instantiate a new quit handler.

type ReadinessHandler

type ReadinessHandler interface {
	NewReadinessHandler() Handle
}

ReadinessHandler is an interface to instantiate a new readiness handler.

type RootHandler

type RootHandler interface {
	NewRootHandler() Handle
}

RootHandler is an interface to instantiate a new root handler.

type Router

type Router struct {
	Router *httprouter.Router
}

Router is a struct that wraps httprouter.Router

type RouterFactory

type RouterFactory interface {
	NewRouter() *Router
}

RouterFactory is an interface to create a new Router.

func NewRouterFactory

func NewRouterFactory() RouterFactory

NewRouterFactory instantiates a new RouterFactory implementation.

type RouterParams

type RouterParams struct {
	Params httprouter.Params
}

RouterParams is a struct that wraps httprouter.Params

type Service

type Service interface {
	Run(ctx context.Context)
	AddRoute(name string, routes []string, methods []string, middlewares []Middleware, handler Handle)
}

Service is the main interface for ServiceFoundation and is used to define routing and running the service.

func NewCustomService

func NewCustomService(options ServiceOptions) Service

NewCustomService allows you to customize ServiceFoundation using your own implementations of factories.

func NewService

func NewService(name string, allowedMethods []string, shutdownFunc ShutdownFunc) Service

NewService creates and returns a Service that uses environment variables for default configuration.

type ServiceGlobals

type ServiceGlobals struct {
	AppName           string
	ServerName        string
	DeployEnvironment string
	VersionNumber     string
}

ServiceGlobals contains basic service properties, like name, deployment environment and version number.

type ServiceHandlerFactory

type ServiceHandlerFactory interface {
	NewHandlers() *Handlers
	WrapHandler
}

ServiceHandlerFactory is an interface to get access to implemented handlers.

func NewServiceHandlerFactory

func NewServiceHandlerFactory(middlewareWrapper MiddlewareWrapper, versionBuilder VersionBuilder,
	stateReader ServiceStateReader, exitFunc ExitFunc) ServiceHandlerFactory

NewServiceHandlerFactory creates a new factory with handler implementations.

type ServiceOptions

type ServiceOptions struct {
	Globals            ServiceGlobals
	Port               int
	ReadinessPort      int
	InternalPort       int
	Logger             Logger
	Metrics            Metrics
	RouterFactory      RouterFactory
	MiddlewareWrapper  MiddlewareWrapper
	Handlers           *Handlers
	WrapHandler        WrapHandler
	VersionBuilder     VersionBuilder
	ServiceStateReader ServiceStateReader
	ShutdownFunc       ShutdownFunc
	ExitFunc           ExitFunc
	ServerTimeout      time.Duration
}

ServiceOptions contains value and references used by the Service implementation. The contents of ServiceOptions can be used to customize or extend ServiceFoundation.

func NewServiceOptions

func NewServiceOptions(name string, allowedMethods []string, shutdownFunc ShutdownFunc) ServiceOptions

NewServiceOptions creates and returns ServiceOptions that use environment variables for default configuration.

func (*ServiceOptions) SetHandlers

func (o *ServiceOptions) SetHandlers()

SetHandlers is used to update the handler references in ServiceOptions to use the correct middleware and state.

type ServiceStateReader

type ServiceStateReader interface {
	IsLive() bool
	IsReady() bool
	IsHealthy() bool
}

ServiceStateReader contains state methods used by the service's handler implementations.

func NewServiceStateReader

func NewServiceStateReader() ServiceStateReader

NewServiceStateReader instantiates a new basic ServiceStateReader implementation, which always returns true for it's state methods.

type ShutdownFunc

type ShutdownFunc func(log Logger)

ShutdownFunc is a function signature for the shutdown function.

type VersionBuilder

type VersionBuilder interface {
	ToString() string
	ToMap() map[string]string
}

VersionBuilder contains methods to output version information in string format.

func NewCustomVersionBuilder

func NewCustomVersionBuilder(version BuildVersion) VersionBuilder

NewCustomVersionBuilder creates and returns a VersionBuilder for the given BuildVersion.

func NewVersionBuilder

func NewVersionBuilder() VersionBuilder

NewVersionBuilder creates and returns a VersionBuilder based on conventional environment variables.

type VersionHandler

type VersionHandler interface {
	NewVersionHandler() Handle
}

VersionHandler is an interface to instantiate a new version handler.

type WrapHandler

type WrapHandler interface {
	Wrap(string, string, []Middleware, Handle) httprouter.Handle
}

WrapHandler is an interface for wrapping a Handle with middleware.

type WrappedResponseWriter

type WrappedResponseWriter interface {
	http.ResponseWriter
	JSON(statusCode int, content interface{})
	XML(statusCode int, content interface{})
	AcceptsXML(r *http.Request) bool
	WriteResponse(r *http.Request, statusCode int, content interface{})
	SetCaching(maxAge int)
	Status() int
}

WrappedResponseWriter is a wrapper around the http.ResponseWriter and extending it with commonly used writing methods.

func NewWrappedResponseWriter

func NewWrappedResponseWriter(w http.ResponseWriter) WrappedResponseWriter

NewWrappedResponseWriter instantiates a new WrappedResponseWriter implementation.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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