ws

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Feb 8, 2019 License: Apache-2.0 Imports: 12 Imported by: 11

Documentation

Overview

Package ws defines types used by framework and application components involved in web service processing. For more information on how web services work in Granitic, see http://granitic.io/1.0/ref/web-services

A brief explanation of the key types and concepts follows.

Requests and responses

WsRequest and WsResponse are abstractions of the HTTP request and response associated with a call to a web service endpoint. By default your application logic will not have access to the underlying HTTP objects (this can be overridden on a per-endpoint basis by setting AllowDirectHTTPAccess to true on your handler - see the package documentation for ws/handler for more information).

Your application code will not directly control how data is parsed into a WsRequest or how the data and/or errors in a WsResponse are rendered to the caller. This is instead handled by the JsonWs or XmlWs facility.

HTTP status codes are determined automatically based on the type (or lack of) errors in the WsResponse object, but this behaviour can be overridden by setting an HTTP status code manually on the WsResponse.

Errors

Errors can be detected or occur during all the phases of request processing (see http://granitic.io/1.0/ref/request-processing-phases). If errors are encountered during the parsing and binding phases of request processing, they are referred to as 'framework errors' as they are handled outside of application code. Framework errors result in one of small number of generic error messages being sent to a caller. See http://granitic.io/1.0/ref/errors-and-messages for information on how to override these messages or how to allow your application to have visibility of framework errors.

If an error occurs during or after parsing and binding is complete, it will be recorded in the WsReponse.Errors field. These types of errors are called service errors. For more information on service errors, refer to the GoDoc for CategorisedError below or http://granitic.io/1.0/ref/errors-and-messages.

Response writing

The serialisation of the data in a WsResponse to an HTTP response is handled by a component implementing WsResponseWriter. A component of this type will be automatically created for you when you enable the JsonWs or XmlWs facility.

Parameter binding

Parameter binding refers to the process of automatically capturing request query parameters and injecting them into fields on the WsRequest Body. It also refers to a similar process for extracting information from a request's path using regular expressions. See http://granitic.io/1.0/ref/parameter-binding for more details.

IAM and versioning

Granitic does not provide implementations of Identity Access Management or request versioning, but instead provides highly generic types to allow your application's implementations of these concepts to be integrated with Grantic's web service request processing. See the GoDoc for WsIdentifier, WsAccessChecker and handler/WsVersionAssessor and the iam package for more details.

HTTP status code determination

Unless your application defines its own HttpStatusCodeDeterminer, the eventual HTTP status code set on the response to a web service request it determined by examining the state of a WsResponse using the following logic:

1. If the WsResponse.HttpStatus field is non-zero, use that.

2. If the WsResponse.Errors.HttpStatus field is non-zero, use that.

3. If the WsResponse.Errors structure:

a) Contains one or more 'Unexpected' errors, use HTTP 500.

b) Contains an 'HTTP' error, convert that error's code to a number and use that.

c) Contains one or more 'Security' errors, use HTTP 401.

d) Contains one or more 'Client' errors, use HTTP 400.

e) Contains one or more 'Logic' errors, use HTTP 409.

4. Return HTTP 200.

Index

Constants

View Source
const (
	// An unhandled error that will generally result in an HTTP 500 status code being set.
	Unexpected = iota

	// A problem that the calling client has caused or could have foreseen, generally resulting in an HTTP 400 status code.
	Client

	// A problem that the calling client could be expected to have foreseen (email addres in use, for example) resulting in an HTTP 409.
	Logic

	// An access or authentication error that might result in an HTTP 401 or 403.
	Security

	// An error that forces a specific HTTP status code.
	HTTP
)
View Source
const (
	// Error encountered while trying to parse an HTTP request body into a struct
	Unmarshall = iota

	// Error encountered while mapping HTTP query parameters to fields on a struct
	QueryBind

	// Error encountered while mapping elements of an HTTP request's path to fields on a struct
	PathBind
)
View Source
const (
	UnableToParseRequest = "UnableToParseRequest"
	QueryTargetNotArray  = "QueryTargetNotArray"
	QueryWrongType       = "QueryWrongType"
	PathWrongType        = "PathWrongType"
	QueryNoTargetField   = "QueryNoTargetField"
)
View Source
const (
	// A normal outcome resulting in an HTTP 200 response.
	Normal = iota

	// A outcome with anticipated and handled errors resulting in a 4xx response.
	Error

	// An unexpected or unusual outcome resulting in a 5xx response.
	Abnormal
)

Variables

This section is empty.

Functions

func CategoryToCode

func CategoryToCode(c ServiceErrorCategory) string

CategoryToCode maps a ServiceErrorCategory to the category's name's first letter. For example, Security maps to 'S'

func CategoryToName

func CategoryToName(c ServiceErrorCategory) string

CategoryToCode maps a ServiceErrorCategory to the category's name's first letter. For example, Security maps to 'Security'

func MergeHeaders

func MergeHeaders(res *WsResponse, ch map[string]string, dh map[string]string) map[string]string

Merges together the headers that have been defined on the WsResponse, the static default headers attache to this writer and (optionally) those constructed by the ws.WsCommonResponseHeaderBuilder attached to this writer. The order of precedence, from lowest to highest, is static headers, constructed headers, headers in the WsResponse.

func WriteHeaders

func WriteHeaders(w http.ResponseWriter, headers map[string]string)

WriteHeaders writes the supplied map as HTTP headers.

Types

type AbnormalStatusWriter

type AbnormalStatusWriter interface {
	// Write converts whatever data is present in the supplied state object to the HTTP output stream associated
	// with the current web service request.
	WriteAbnormalStatus(ctx context.Context, state *WsProcessState) error
}

Implemented by components able to write a valid response even if the request resulted in an abnormal (5xx) outcome.

type CategorisedError

type CategorisedError struct {
	// The broad type of error, which influences the eventual HTTP status code set on the response.
	Category ServiceErrorCategory

	// A unique code that a caller can rely on to identify a specific error or that can be used to lookup an error message.
	Code string

	// A message suitable for displaying to the caller.
	Message string

	//If this error relates to a specific field or parameter in a web service request, this field is set to the name of that field.
	Field string
}

A service error with a concept of the general 'type' of error it is.

func NewCategorisedError

func NewCategorisedError(category ServiceErrorCategory, code string, message string) *CategorisedError

NewCategorisedError creates a new CategorisedError with every field expect 'Field' set.

type DirectHTTPAccess

type DirectHTTPAccess struct {
	// The HTTP response output stream.
	ResponseWriter http.ResponseWriter

	// The incoming HTTP request.
	Request *http.Request
}

Wraps the underlying low-level HTTP request and response writing objects.

type ErrorFormatter

type ErrorFormatter interface {
	// FormatErrors converts the supplied errors into a structure that a response writer will use to write the errors to
	// the current HTTP response.
	FormatErrors(errors *ServiceErrors) interface{}
}

Interface for components able to convert a set of service errors into a structure suitable for serialisation.

type FrameworkErrorEvent

type FrameworkErrorEvent string

Uniquely identifies a 'handled' failure during the parsing and binding phases

type FrameworkErrorGenerator

type FrameworkErrorGenerator struct {
	Messages        map[FrameworkErrorEvent][]string
	HttpMessages    map[string]string
	FrameworkLogger logging.Logger
}

A FrameworkErrorGenerator can create error messages for errors that occur outside of application code and messages that should be displayed when generic HTTP status codes (404, 500, 503 etc) are set.

func (*FrameworkErrorGenerator) Error

Error creates a service error given a framework error.

func (*FrameworkErrorGenerator) HttpError

func (feg *FrameworkErrorGenerator) HttpError(status int, a ...interface{}) *CategorisedError

HttpError generates a message to be displayed to a caller when a generic HTTP status (404 etc) is encountered. If an error message is not defined for the supplied status, the message "HTTP (code)" is returned, e.g. "HTTP 101"

func (*FrameworkErrorGenerator) MessageCode

func (feg *FrameworkErrorGenerator) MessageCode(e FrameworkErrorEvent, a ...interface{}) (message string, code string)

MessageCode returns a message and code for a Framework error event (leaving the caller to create a CategorisedError)

type GraniticHttpStatusCodeDeterminer

type GraniticHttpStatusCodeDeterminer struct {
}

The default HttpStatusCodeDeterminer used by Granitic's XXXWs facilities. See the top of this page for rules on how this code is determined.

func (*GraniticHttpStatusCodeDeterminer) DetermineCode

func (dhscd *GraniticHttpStatusCodeDeterminer) DetermineCode(response *WsResponse) int

DetermineCode examines the response and returns an HTTP status code according to the rules defined at the top of this GoDoc page.

type HttpStatusCodeDeterminer

type HttpStatusCodeDeterminer interface {
	// DetermineCode returns the HTTP status code that should be set on the response.
	DetermineCode(response *WsResponse) int
}

Implemented by a component able to choose the most appropriate HTTP status code to set given the state of a WsResponse

type MarshalingWriter

type MarshalingWriter interface {

	// MarshalAndWrite converts the data to some serialisable form (JSON, XML etc) and writes it to the HTTP output stream.
	MarshalAndWrite(data interface{}, w http.ResponseWriter) error
}

Implemented by components that can convert the supplied data into a form suitable for serialisation and write that serialised form to the HTTP output stream.

type MarshallingResponseWriter

type MarshallingResponseWriter struct {
	// Injected automatically
	FrameworkLogger logging.Logger

	// Component able to calculate the HTTP status code that should be written to the HTTP response.
	StatusDeterminer HttpStatusCodeDeterminer

	// Component able to generate errors if a problem is encountered during marshalling.
	FrameworkErrors *FrameworkErrorGenerator

	// The common and static set of headers that should be written to all responses.
	DefaultHeaders map[string]string

	// Component able to wrap response data in a standardised structure.
	ResponseWrapper ResponseWrapper

	// Component able to dynamically generate additional headers to be written to the response.
	HeaderBuilder WsCommonResponseHeaderBuilder

	// Component able to format services errors in an application specific manner.
	ErrorFormatter ErrorFormatter

	// Component able to serialize the data to the HTTP output stream.
	MarshalingWriter MarshalingWriter
}

A response writer that uses automatic marshalling of structs to serialisable forms rather than using templates.

func (*MarshallingResponseWriter) Write

func (rw *MarshallingResponseWriter) Write(ctx context.Context, state *WsProcessState, outcome WsOutcome) error

See WsResponseWriter.Write

func (*MarshallingResponseWriter) WriteAbnormalStatus

func (rw *MarshallingResponseWriter) WriteAbnormalStatus(ctx context.Context, state *WsProcessState) error

See AbnormalStatusWriter.WriteAbnormalStatus

type ParamBinder

type ParamBinder struct {
	// Injected by Granitic
	FrameworkLogger logging.Logger

	// Source of service errors for errors encountered while binding.
	FrameworkErrors *FrameworkErrorGenerator
}

Takes string parameters extracted from an HTTP request, converts them to Go native or Granitic nilable types and injects them into the RequestBody on a WsRequest.

func (*ParamBinder) AutoBindQueryParameters

func (pb *ParamBinder) AutoBindQueryParameters(wsReq *WsRequest)

BindPathParameters takes the query parameters from an HTTP request and injects them into fields on the WsRequest.RequestBody assuming the parameters have exactly the same name as the target fields. Any errors encountered are recorded as framework errors in the WsRequest.

func (*ParamBinder) BindPathParameters

func (pb *ParamBinder) BindPathParameters(wsReq *WsRequest, p *WsParams)

BindPathParameters takes strings extracted from an HTTP's request path (using regular expression groups) and injects them into fields on the WsRequest.RequestBody. Any errors encountered are recorded as framework errors in the WsRequest.

func (*ParamBinder) BindQueryParameters

func (pb *ParamBinder) BindQueryParameters(wsReq *WsRequest, targets map[string]string)

BindPathParameters takes the query parameters from an HTTP request and injects them into fields on the WsRequest.RequestBody using the keys of the supplied map as the name of the target fields. Any errors encountered are recorded as framework errors in the WsRequest.

type ResponseWrapper

type ResponseWrapper interface {
	// WrapResponse takes the supplied body and errors and wraps them in a standardised data structure.
	WrapResponse(body interface{}, errors interface{}) interface{}
}

Implemented by components able to take the body from an WsResponse and wrap it inside a container that will allow all responses to share a common structure.

type ServiceErrorCategory

type ServiceErrorCategory int

The broad 'type' of a service error, used to determine the correct HTTP status code to use.

func CodeToCategory

func CodeToCategory(c string) (ServiceErrorCategory, error)

CodeToCategory takes the short form of a category's name (its first letter, capitialised) an maps that to a ServiceErrorCategory

type ServiceErrorConsumer

type ServiceErrorConsumer interface {
	// ProvideErrorFinder receives a ServiceErrorFinder
	ProvideErrorFinder(finder ServiceErrorFinder)
}

Implemented by components that require a ServiceErrorFinder to be injected into them

type ServiceErrorFinder

type ServiceErrorFinder interface {
	//Find takes a code and returns the message and category for that error. Behaviour undefined if code is not
	// recognised.
	Find(code string) *CategorisedError
}

Implemented by a component that is able to find a message and error category given the code for an error

type ServiceErrors

type ServiceErrors struct {
	// All services found, in the order in which they occured.
	Errors []CategorisedError

	// An externally computed HTTP status code that reflects the mix of errors in this structure.
	HttpStatus int

	// A component able to find additional information about error from that error's unique code.
	ErrorFinder ServiceErrorFinder
}

A structure that records each of the errors found during the processing of a request.

func (*ServiceErrors) AddError

func (se *ServiceErrors) AddError(e *CategorisedError)

AddError records the supplied error.

func (*ServiceErrors) AddNewError

func (se *ServiceErrors) AddNewError(category ServiceErrorCategory, label string, message string)

AddNewError creates a new CategorisedError from the supplied information and captures it.

func (*ServiceErrors) AddPredefinedError

func (se *ServiceErrors) AddPredefinedError(code string, field ...string) error

AddPredefinedError creates a CategorisedError by looking up the supplied code and records that error. If the variadic field parameter is supplied, the created error will be associated with that field name.

func (*ServiceErrors) HasErrors

func (se *ServiceErrors) HasErrors() bool

HasErrors returns true if one or more errors have been encountered and recorded.

type WsAccessChecker

type WsAccessChecker interface {
	// Allowed returns true if the caller is allowed to have this request processed, false otherwise.
	Allowed(ctx context.Context, r *WsRequest) bool
}

WsIdentifier is implemented by components that are able to determine if a caller is allowed to have a request processed.

type WsCommonResponseHeaderBuilder

type WsCommonResponseHeaderBuilder interface {
	BuildHeaders(ctx context.Context, state *WsProcessState) map[string]string
}

An object that constructs response headers that are common to all web service requests. These may typically be caching instructions or 'processing server' records. Implementations must be extremely cautious when using the information in the supplied WsProcess state as some values may be nil.

type WsFrameworkError

type WsFrameworkError struct {
	// The phase of the request processing during which an error was encountered.
	Phase WsFrameworkPhase

	// The name of the field or parameter in the HTTP request with a problem
	ClientField string

	// The name of the field on the response body struct that was being written to
	TargetField string

	// A system generated message relating to the error.
	Message string

	// The value of the field/parameter that caused the error.
	Value string

	// For array parameters, the position in the array that caused the error.
	Position int

	// A system generated code for the error.
	Code string
}

An error encountered in early phases of request processing, before application code is invoked.

func NewPathBindFrameworkError

func NewPathBindFrameworkError(message, code, target string) *WsFrameworkError

NewPathBindFrameworkError creates a WsFrameworkError with fields set appropriate for an error encountered during mapping elements of the HTTP request's path to fields on a WsRequest's Body.

func NewQueryBindFrameworkError

func NewQueryBindFrameworkError(message, code, param, target string) *WsFrameworkError

NewQueryBindFrameworkError creates a WsFrameworkError with fields set appropriate for an error encountered during mapping of HTTP query parameters to fields on a WsRequest's Body

func NewUnmarshallWsFrameworkError

func NewUnmarshallWsFrameworkError(message, code string) *WsFrameworkError

NewUnmarshallWsFrameworkError creates a WsFrameworkError with fields set appropriate for an error encountered during parsing of the HTTP request body.

type WsFrameworkPhase

type WsFrameworkPhase int

The phase of the request processing during which an error was encountered.

type WsIdentifier

type WsIdentifier interface {
	// Identify returns information about the caller derived request and a Context that might be different from the supplied Context.
	Identify(ctx context.Context, req *http.Request) (iam.ClientIdentity, context.Context)
}

WsIdentifier is implemented by components that are able to identify a caller based on a raw HTTP request (normally from headers and cookies). Implementations of this interface may return a new Context that supersedes the supplied Context.

type WsOutcome

type WsOutcome uint

An enumeration of the high-level result of processing a request. Used internally.

type WsParams

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

An abstraction of the HTTP query parameters or path parameters with type-safe accessors.

func NewWsParamsForPath

func NewWsParamsForPath(targets []string, values []string) *WsParams

NewWsParamsForPath creates a WsParams used to store the elements of a request path extracted using regular expression groups.

func NewWsParamsForQuery

func NewWsParamsForQuery(values url.Values) *WsParams

NewWsParamsForQuery creates a WsParams storing the HTTP query parameters from a request.

func (*WsParams) BoolValue

func (wp *WsParams) BoolValue(key string) (bool, error)

BoolValue returns the bool representation of the specified parameter (using Go's bool conversion rules) or an error if no value exists for that parameter.

func (*WsParams) Exists

func (wp *WsParams) Exists(key string) bool

Exists returns true if a parameter with the supplied name exists, even if that parameter's value is an empty string.

func (*WsParams) FloatNValue

func (wp *WsParams) FloatNValue(key string, bits int) (float64, error)

FloatNValue returns a float representation of the specified parameter with the specified bit size, or an error if no value exists for that parameter or if the value could not be converted to a float.

func (*WsParams) IntNValue

func (wp *WsParams) IntNValue(key string, bits int) (int64, error)

IntNValue returns a signed int representation of the specified parameter with the specified bit size, or an error if no value exists for that parameter or if the value could not be converted to an int.

func (*WsParams) MultipleValues

func (wp *WsParams) MultipleValues(key string) bool

MultipleValues returns true if the parameter with the supplied name was set more than once (allowed for HTTP query parameters).

func (*WsParams) NotEmpty

func (wp *WsParams) NotEmpty(key string) bool

NotEmpty returns true if a parameter with the supplied name exists and has a non-empty string representation.

func (*WsParams) ParamNames

func (wp *WsParams) ParamNames() []string

ParamNames returns the names of all of the parameters stored

func (*WsParams) StringValue

func (wp *WsParams) StringValue(key string) (string, error)

StringValue returns the string representation of the specified parameter or an error if no value exists for that parameter.

func (*WsParams) UIntNValue

func (wp *WsParams) UIntNValue(key string, bits int) (uint64, error)

UIntNValue returns an unsigned int representation of the specified parameter with the specified bit size, or an error if no value exists for that parameter or if the value could not be converted to an unsigned int.

type WsProcessState

type WsProcessState struct {
	// The representation of the incoming request at the time processing completed or failed.
	WsRequest *WsRequest

	// The representation of the data to be sent to the caller at the time processing completed or failed.
	WsResponse *WsResponse

	// The HTTP output stream.
	HttpResponseWriter *httpendpoint.HttpResponseWriter

	// Errors detected while processing the web service request. If set, supersedes the errors present in WsResponse field.
	ServiceErrors *ServiceErrors

	// Information about the caller or user of the web service.
	Identity iam.ClientIdentity

	// The HTTP status code to be set on the HTTP response.
	Status int
}

WsProcessState is wrapper for current state of request processing. This type is used by components implementing WsResponseWriter. Because a request may fail at many points during processing, there is no guarantee that any of the fields in this type are set, valid or complete, so this type must be used with caution.

func NewAbnormalState

func NewAbnormalState(status int, w *httpendpoint.HttpResponseWriter) *WsProcessState

NewAbnormalState creates a new WsProcessState for a request that has resulted in an abnormal (HTTP 5xx) outcome).

type WsRequest

type WsRequest struct {
	// The HTTP method (GET, POST etc) of the underlying HTTP request.
	HttpMethod string

	// If the HTTP request had a body and if the handler that generated this WsRequest implements WsUnmarshallTarget,
	// then RequestBody will contain a struct representation of the request body.
	RequestBody interface{}

	// A copy of the HTTP query parameters from the underlying HTTP request with type-safe accessors.
	QueryParams *WsParams

	// Information extracted from the path portion of the HTTP request using regular expression groups with type-safe accessors.
	PathParams []string

	// Problems encountered during the parsing and binding phases of request processing.
	FrameworkErrors []*WsFrameworkError

	// Information about the web service caller (if the handler has a WsIdentifier).
	UserIdentity iam.ClientIdentity

	//The underlying HTTP request and response  (if the handler was configured to pass
	// this information on).
	UnderlyingHTTP *DirectHTTPAccess

	//The component name of the handler that generated this WsRequest.
	ServingHandler string
	// contains filtered or unexported fields
}

Stores information about a web service request that has been either copied in or derived from an underlying HTTP request.

func (*WsRequest) AddFrameworkError

func (wsr *WsRequest) AddFrameworkError(f *WsFrameworkError)

AddFrameworkError records a framework error.

func (*WsRequest) BoundFields

func (wsr *WsRequest) BoundFields() types.StringSet

BoundFields returns the name of all of the names on the RequestBody that were explicitly set by the query/path parameter binding process.

func (*WsRequest) HasFrameworkErrors

func (wsr *WsRequest) HasFrameworkErrors() bool

HasFrameworkErrors returns true if one or more framework errors have been recorded.

func (*WsRequest) RecordFieldAsBound

func (wsr *WsRequest) RecordFieldAsBound(fieldName string)

RecordFieldAsBound is used to record the fact that a field on the RequestBody was explicitly set by the query/path parameter binding process.

func (*WsRequest) WasFieldBound

func (wsr *WsRequest) WasFieldBound(fieldName string) bool

WasFieldBound returns true if a field on the RequestBody was explicitly set by the query/path parameter binding process.

type WsResponse

type WsResponse struct {
	// An instruction that the HTTP status code should be set to this value (if the value is greater than 99). Generally
	// not set - the response writer will determine the correct status to use.
	HttpStatus int

	// If the web service call resulted in data that should be written as the body of the HTTP response is stored in this field.
	// Application code must set this field explicitly.
	Body interface{}

	// All of the errors encountered while processing this request.
	Errors *ServiceErrors

	// Headers that should be set on the HTTP response.
	Headers map[string]string

	// If the type of response rendering is template based (e.g. using the XmlWs facility in template mode), this field
	// can be used to override any default templates or the template associated with the handler that created this response.
	Template string
}

Contains data that is relevant to the rendering of the result of a web service request to an HTTP response. This type is agnostic of the format (JSON, XML etc) that is to be used to render the response.

func NewWsResponse

func NewWsResponse(errorFinder ServiceErrorFinder) *WsResponse

NewWsResponse creates a valid but empty WsReponse with Errors structure initialised.

type WsResponseWriter

type WsResponseWriter interface {
	// Write converts whatever data is present in the supplied state object to the HTTP output stream associated
	// with the current web service request.
	Write(ctx context.Context, state *WsProcessState, outcome WsOutcome) error
}

Implemented by components able write the result of a web service call to an HTTP response.

type WsUnmarshaller

type WsUnmarshaller interface {
	// Unmarshall deserialises an HTTP request body and converts it to a struct.
	Unmarshall(ctx context.Context, req *http.Request, wsReq *WsRequest) error
}

Implement by components that are able to convert an HTTP request body into a struct.

Directories

Path Synopsis
Package handler provides the types used to coordinate the processing of a web service request.
Package handler provides the types used to coordinate the processing of a web service request.
Package json defines types that are specific to handling web service requests and responses as JSON.
Package json defines types that are specific to handling web service requests and responses as JSON.
Package xml defines types that are specific to handling web service requests and responses as XML.
Package xml defines types that are specific to handling web service requests and responses as XML.

Jump to

Keyboard shortcuts

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