restapi

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Sep 9, 2024 License: MIT Imports: 16 Imported by: 1

Documentation

Overview

Package restapi provides a set of helpers to implement REST API following Acronis REST API Guidelines.

Index

Examples

Constants

View Source
const ContentTypeAppJSON = "application/json"

ContentTypeAppJSON represents MIME media type for JSON.

View Source
const ContentTypeAppSCIMJSON = "application/scim+json"

ContentTypeAppSCIMJSON represents MIME media type for SCIM JSON.

Variables

View Source
var (
	ErrCodeInternal         = "internalError"
	ErrCodeNotFound         = "notFound"
	ErrCodeMethodNotAllowed = "methodNotAllowed"
)

Error codes. We are using "var" here because some services may want to use different error codes.

View Source
var (
	ErrMessageInternal         = "Internal error."
	ErrMessageNotFound         = "Not found."
	ErrMessageMethodNotAllowed = "Method not allowed."
)

Error messages. We are using "var" here because some services may want to use different error messages.

Functions

func DecodeRequestJSON

func DecodeRequestJSON(r *http.Request, dst interface{}) error

DecodeRequestJSON tries to read request body and decode it as JSON.

Example
type User struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

const domain = "MyService"

http.HandleFunc("/endpoint", func(w http.ResponseWriter, r *http.Request) {
	var user User
	if err := DecodeRequestJSON(r, &user); err != nil {
		logger := log.NewDisabledLogger()

		var reqErr *MalformedRequestError
		if errors.As(err, &reqErr) {
			RespondMalformedRequestError(w, domain, reqErr, logger)
			return
		}

		RespondError(w, http.StatusInternalServerError, NewInternalError(domain), logger)
		return
	}
})
Output:

func DecodeRequestJSONStrict

func DecodeRequestJSONStrict(r *http.Request, dst interface{}, disallowUnknownFields bool) error

DecodeRequestJSONStrict tries to read and validate request fields in body and decode it as JSON.

func DisableWrappingErrorInResponse

func DisableWrappingErrorInResponse()

DisableWrappingErrorInResponse disables wrapping error ({"error": {"domain": "{domain}", ...} -> {"domain": "{domain}", ...}) in response body.

func DoRequest

func DoRequest(client *http.Client, req *http.Request, logger log.FieldLogger) (*http.Response, error)

DoRequest allows to do HTTP requests and log some its details

func DoRequestAndUnmarshalJSON

func DoRequestAndUnmarshalJSON(client *http.Client, req *http.Request, result interface{}, logger log.FieldLogger) error

DoRequestAndUnmarshalJSON allows doing HTTP requests, log some its details and unmarshal response

func MustInitAndRegisterMetrics

func MustInitAndRegisterMetrics(namespace string)

MustInitAndRegisterMetrics initializes and registers restapi global metrics. Panic will be raised in case of error.

func NewJSONRequest

func NewJSONRequest(method, url string, data interface{}) (*http.Request, error)

NewJSONRequest performs JSON marshaling of the passed data and creates a new http.Request

func NormalizeURLPath

func NormalizeURLPath(urlPath string) string

NormalizeURLPath normalizes URL path (i.e. for example, it convert /foo///bar/.. to /foo).

func RespondCodeAndJSON

func RespondCodeAndJSON(rw http.ResponseWriter, statusCode int, respData interface{}, logger log.FieldLogger)

RespondCodeAndJSON sends a response with the passed status code and sets the "Content-Type" to "application/json" if it's not already set. It performs JSON marshaling of the data and writes the result to the response's body.

func RespondError

func RespondError(rw http.ResponseWriter, httpStatusCode int, err *Error, logger log.FieldLogger)

RespondError sets HTTP status code in response and writes error in body in JSON format. Also, it logs info (code and message) about error.

Example
http.HandleFunc("/endpoint", func(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		apiErr := NewError("MyService", "methodNotAllowed", "Only GET HTTP method is allowed.")
		RespondError(w, http.StatusMethodNotAllowed, apiErr, log.NewDisabledLogger())
		return
	}
})
Output:

func RespondInternalError

func RespondInternalError(rw http.ResponseWriter, domain string, logger log.FieldLogger)

RespondInternalError sends response with 500 HTTP status code and internal error in body in JSON format.

func RespondJSON

func RespondJSON(rw http.ResponseWriter, respData interface{}, logger log.FieldLogger)

RespondJSON sends response with 200 HTTP status code, does JSON marshaling of data and writes result in response's body.

Example
http.HandleFunc("/endpoint", func(w http.ResponseWriter, r *http.Request) {
	type User struct {
		Name string `json:"name"`
		Age  int    `json:"age"`
	}
	RespondJSON(w, &User{Name: "Bob", Age: 12}, log.NewDisabledLogger())
})
Output:

func RespondMalformedRequestError

func RespondMalformedRequestError(rw http.ResponseWriter, domain string, reqErr *MalformedRequestError, logger log.FieldLogger)

RespondMalformedRequestError creates Error from passed MalformedRequestError and then call RespondError.

func RespondMalformedRequestOrInternalError

func RespondMalformedRequestOrInternalError(rw http.ResponseWriter, domain string, err error, logger log.FieldLogger)

RespondMalformedRequestOrInternalError calls RespondMalformedRequestError (if passed error is *MalformedRequestError) or RespondInternalError (in other cases).

func RespondNoWrappedError

func RespondNoWrappedError(rw http.ResponseWriter, httpStatusCode int, err *Error, logger log.FieldLogger)

RespondNoWrappedError sets HTTP status code in response and writes non-wrapped error in body in JSON format. Also, it logs info (code and message) about error.

func RespondWrappedError

func RespondWrappedError(rw http.ResponseWriter, httpStatusCode int, err *Error, logger log.FieldLogger)

RespondWrappedError sets HTTP status code in response and writes wrapped error in body in JSON format. Also, it logs info (code and message) about error.

func SetRequestMaxBodySize

func SetRequestMaxBodySize(w http.ResponseWriter, r *http.Request, maxSizeBytes uint64)

SetRequestMaxBodySize wraps request body with a reader which limit the number of bytes to read. RequestBodyTooLargeError will be returned when maxSizeBytes is exceeded.

func UnregisterMetrics

func UnregisterMetrics()

UnregisterMetrics unregisters restapi global metrics.

Types

type ClientError

type ClientError struct {
	Message    string
	Method     string
	URL        *url.URL
	StatusCode int
	Err        error
}

ClientError - error that can be returned in request to client

func (*ClientError) Error

func (e *ClientError) Error() string

Error - impelent error interface

func (*ClientError) Is

func (e *ClientError) Is(target error) bool

Is - allow check it with errors.Is

func (*ClientError) Unwrap

func (e *ClientError) Unwrap() error

Unwrap - allow check it with errors.As

type Error

type Error struct {
	Domain  string                 `json:"domain"`
	Code    string                 `json:"code"`
	Message string                 `json:"message,omitempty"`
	Context map[string]interface{} `json:"context,omitempty"`
	KbLink  *KBLinkInfo            `json:"kbLink,omitempty"`
	Debug   map[string]interface{} `json:"debug,omitempty"`
}

Error represents an error details.

func NewError

func NewError(domain, code, message string) *Error

NewError creates a new Error with specified params.

func NewInternalError

func NewInternalError(domain string) *Error

NewInternalError creates a new internal error with specified domain.

func (*Error) AddContext

func (e *Error) AddContext(field string, value interface{}) *Error

AddContext adds value to error context.

func (*Error) AddDebug

func (e *Error) AddDebug(field string, value interface{}) *Error

AddDebug adds value to debug info.

type ErrorResponseData

type ErrorResponseData struct {
	Err *Error `json:"error"`
}

ErrorResponseData is used for answer on requests with error

func (*ErrorResponseData) Error

func (e *ErrorResponseData) Error() string

type KBLinkInfo

type KBLinkInfo struct {
	LineTag string `json:"lineTag,omitempty"`
	SerCode string `json:"serCode,omitempty"`
	Version string `json:"version,omitempty"`
	Build   string `json:"build,omitempty"`
	Product string `json:"product,omitempty"`
	Os      string `json:"os,omitempty"`
}

KBLinkInfo represents an info about item in Acronis Knowledge Base.

type MalformedRequestError

type MalformedRequestError struct {
	HTTPStatusCode int
	Message        string
}

MalformedRequestError is an error that occurs in case of incorrect request.

func NewTooLargeMalformedRequestError

func NewTooLargeMalformedRequestError(maxSizeBytes uint64) *MalformedRequestError

NewTooLargeMalformedRequestError creates a new MalformedRequestError for case when request body is too large.

func (*MalformedRequestError) Error

func (e *MalformedRequestError) Error() string

Error returns a string representation of MalformedRequestError.

type RequestBodyTooLargeError

type RequestBodyTooLargeError struct {
	MaxSizeBytes uint64
	Err          error
}

RequestBodyTooLargeError represents an error that occurs when read number of bytes (HTTP request body) exceeds the specified limit.

func (*RequestBodyTooLargeError) Error

func (e *RequestBodyTooLargeError) Error() string

Error returns a string representation of RequestBodyTooLargeError.

type Route

type Route struct {
	Path        RoutePath
	Methods     []string
	Handler     http.Handler
	Middlewares []func(http.Handler) http.Handler
	Excluded    bool // Set to true for routes that are matched to be excluded.
}

Route represents route for handling.

func NewExcludedRoute

func NewExcludedRoute(cfg RouteConfig) Route

NewExcludedRoute returns a new route that will be used as exclusion in matching.

func NewRoute

func NewRoute(cfg RouteConfig, handler http.Handler, middlewares []func(http.Handler) http.Handler) Route

NewRoute returns a new route.

type RouteConfig

type RouteConfig struct {
	// Path is a struct that contains info about route path.
	// ParseRoutePath function should be used for constructing it from the string representation.
	Path RoutePath `mapstructure:"path"`

	// Methods is a list of case-insensitive HTTP verbs/methods.
	Methods []string `mapstructure:"methods"`
}

RouteConfig represents route's configuration.

func (*RouteConfig) MethodsInUpperCase

func (r *RouteConfig) MethodsInUpperCase() []string

MethodsInUpperCase returns list of route's methods in upper-case.

func (*RouteConfig) Validate

func (r *RouteConfig) Validate() error

Validate validates RouteConfig

type RoutePath

type RoutePath struct {
	Raw            string
	NormalizedPath string
	RegExpPath     *regexp.Regexp
	ExactMatch     bool
	ForwardMatch   bool
}

RoutePath represents route's path.

func ParseRoutePath

func ParseRoutePath(rp string) (RoutePath, error)

ParseRoutePath parses string representation of route's path. Syntax: [ = | ~ | ^~ ] urlPath Semantic for modifier is used the same as in Nginx (https://nginx.org/en/docs/http/ngx_http_core_module.html#location).

func (*RoutePath) UnmarshalText

func (rp *RoutePath) UnmarshalText(text []byte) (err error)

UnmarshalText implements the encoding.TextUnmarshaler interface.

type RoutesManager

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

RoutesManager contains routes for handling and allows to search among them.

func NewRoutesManager

func NewRoutesManager(routes []Route) *RoutesManager

NewRoutesManager create new RoutesManager.

func (*RoutesManager) SearchMatchedRouteForRequest

func (r *RoutesManager) SearchMatchedRouteForRequest(req *http.Request) (Route, bool)

SearchMatchedRouteForRequest searches Route that matches the passing http.Request. Algorithm is the same as used in Nginx for locations matching (https://nginx.org/en/docs/http/ngx_http_core_module.html#location). Excluded routes has priority.

func (*RoutesManager) SearchRoute

func (r *RoutesManager) SearchRoute(normalizedPath string, method string, excluded bool) (Route, bool)

SearchRoute searches Route by passed path and method. Path should be normalized (see NormalizeURLPath for this). If the excluded arg is true, search will be done only among excluded routes. If false - only among included routes. nolint:gocyclo

Jump to

Keyboard shortcuts

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