bark

package
v0.1.10 Latest Latest
Warning

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

Go to latest
Published: Apr 24, 2024 License: Apache-2.0 Imports: 9 Imported by: 0

README

SRE-Norns: Wyrd/Bark!

Reusable REST API components that you need to extend (Gin-gonic)[github.com/gin-gonic/gin]!

This go-module provides a number types, helpers and filters that are very handy when creating rich Rest API using popular Go web framework.

Usage

Using search filters allows to have standard API with filter labels and pagination:

    // Define API that allows filters and returns paginated response
    api.GET("/artifacts", bark.SearchableAPI(paginationLimit), ..., func(ctx *gin.Context) {
        // Extract search query from the context:
        searchQuery := bark.RequireSearchQuery(ctx)

        // Use the query in your API;
        results, err := service.GetArtifactsApi().List(ctx.Request.Context(), searchQuery)
        ... 
    })

Middleware

The library offers a collection of middleware / filter that streamline implementation of a service responsible for a collection of resource.

  • ContentTypeAPI - enables API to support different serialization formats, respecting Accept HTTP Request headers.
  • SearchableAPI - enables APIs to support query filter and pagination.
  • AuthBearerAPI - enables APIs to read Auth Bearer token.
  • ResourceAPI - streamline implementation of APIs that serves a single resource.
  • VersionedResourceAPI - enables API implementation that can support request to versioned resources.
  • ManifestAPI - helps to streamline implementation of APIs that detail with manifest.Resource
Middleware: ContentTypeAPI

This function returns gin.HandlerFunc as middleware to add support for response marshaler selection based on Accept HTTP Request header.

It is expected to be used in conjunction with bark.MarshalResponse and bark.ReplyResourceCreated method that select recommended marshaler method to be used for http response.

For example, a client can call /artifacts/:id API with Accept header to inform the server what response type is expected back. Given valid request, for example:

GET /artifacts/:id HTTP/1.1
Host: localhost:8080
Accept: application/xml

The server would select XML as serialization method:

HTTP/1.1 200 OK
Content-Type: application/xml; charset=utf-8

....
Usage:
    api.GET("/artifacts/:id", bark.ContentTypeAPI(), func(ctx *gin.Context) {
        ...

        bark.MarshalResponse(ctx, http.StatusOK, resource) // NOTE: To use this method ContentTypeAPI middleware is required
    })

    v1.POST("/artifacts", bark.ContentTypeAPI(), func(ctx *gin.Context) {
        ...
        
        bark.ReplyResourceCreated(ctx, result.ID, result) // NOTE: To use this method ContentTypeAPI middleware is required
    })

Middleware: SearchableAPI

This function returns gin.HandlerFunc as middleware to add support pagination query parameters and labels query parameters. The idea is that Rest APIs that returns a collection of results should support pagination and ability to narrows down a dataset returned.

Typical implementation takes shape of query parameters such as filter and page numbers.

Using SearchableAPI() gives users ability to call RequireSearchQuery to get an object representing search query passed by clients. Note that RequireSearchQuery will panic if there was not SearchableAPI call in the filter chain to add query object to the context.

Usage:

Assuming the server has /artifacts REST endpoint that is meant to return a collection of artifacts / objects. With SearchableAPI middleware, clients can use labels and page query parameters to control pagination and filter.

GET /artifacts?labels=key&page=3 HTTP/1.1

To support the above query parameters, following code should be added to the handler:

    api.GET("/artifacts", bark.SearchableAPI(), func(ctx *gin.Context) {
        ...
        searchQuery := bark.RequireSearchQuery(ctx) 

        results := myservice.Find(ctx, searchQuery)
        ...

    })
Middleware: AuthBearerAPI

enables APIs to read Auth Bearer token.

Middleware: ResourceAPI

Streamline implementation of APIs that serves a single resource.

Middleware: VersionedResourceAPI

Enables API implementation that can support request to versioned resources.

Middleware: ManifestAPI

Helps to streamline implementation of APIs that detail with manifest.Resource

Documentation

Index

Constants

View Source
const (

	// well known HTTP headers
	// HTTPHeaderAuth is a standard [header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) to communicate authorization information
	HTTPHeaderAuth = "Authorization"

	// HTTPHeaderAccept is a standard [header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) communicating media format expected by the client
	HTTPHeaderAccept = "Accept"

	// HTTPHeaderLocation is a standard [header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location) returns location of a newly created resource.
	HTTPHeaderLocation = "Location"

	// HTTPHeaderContentType is a standard [header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) inform server of how to interpret request body.
	HTTPHeaderContentType = "Content-Type"

	// HTTPHeaderCacheControl is a standard [header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) inform client about caching options for the response received
	HTTPHeaderCacheControl = "Cache-Control"
)

Variables

View Source
var (
	// ErrUnsupportedMediaType error indicates that [Content-Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) passed in a client request is not support by the API / endpoint.
	ErrUnsupportedMediaType = fmt.Errorf("unsupported content type request")
	// ErrInvalidAuthHeader error indicates incorrectly former [Authorization](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) header in the message.
	ErrInvalidAuthHeader = fmt.Errorf("invalid Authorization header")
	// ErrWrongKind error indicates that [manifest.Kind] passed to an endpoint is not expected by that endpoint.
	ErrWrongKind = fmt.Errorf("invalid resource kind for the API")

	// ErrResourceNotFound represents error response when requested resource not found.
	ErrResourceNotFound = &ErrorResponse{Code: http.StatusNotFound, Message: "requested resource not found"}
)

Functions

func AbortWithError

func AbortWithError(ctx *gin.Context, code int, errValue error)

AbortWithError terminates response-handling chain with an error, and returns provided HTTP error response to the client

func AuthBearerAPI

func AuthBearerAPI() gin.HandlerFunc

AuthBearerAPI return a middleware that extracts "Bearer" token from an incoming request headers. The middleware terminates call chain and return http.StatusUnauthorized to a client if there is no HTTPHeaderAuth headers set. Note the middleware does not check if the token is "valid", only that it has been set. See RequireBearerToken for information on how to access the token.

func ContentTypeAPI

func ContentTypeAPI() gin.HandlerFunc

ContentTypeAPI returns middleware to support response marshaler selection based on HTTPHeaderAccept value. Used in conjunction with MarshalResponse and ReplyResourceCreated

func Found added in v0.1.6

func Found[T any](ctx *gin.Context, results []T, options ...HResponseOption)

Found is a shortcut to produce 200/Ok response for paginated data using NewPaginatedResponse to wrap items into Pagination frame.

func FoundOrNot added in v0.1.8

func FoundOrNot[T any](ctx *gin.Context, err error, results []T, options ...HResponseOption)

FoundOrNot checks error value and response with error or using Found function if no error.

func ManifestAPI

func ManifestAPI(kind manifest.Kind) gin.HandlerFunc

ManifestAPI returns middleware that extract manifest.ResourceManifest from an incoming request body. HTTPHeaderContentType is used for content-type negotiation. Note, the call is terminated if incorrect [manifest.kind] is passed to the API. Refer to RequireManifest to get extract manifest form the call context.

func MarshalResponse

func MarshalResponse(ctx *gin.Context, code int, responseValue any)

MarshalResponse selects appropriate resource marshaler based on HTTPHeaderAccept request header value and marshals response object.

func MaybeGotOne added in v0.1.8

func MaybeGotOne(ctx *gin.Context, resource any, exists bool, err error)

MaybeGotOne checks usual API returned value if requested object exists, if there was an error during the request and if all good response Ok with requested resource marshaled using MarshalResponse function.

func Ok added in v0.1.8

func Ok(ctx *gin.Context, resource any)

Ok writes HTTP/OK 200 response and marshals response object with MarshalResponse function

func ReplyResourceCreated

func ReplyResourceCreated(ctx *gin.Context, id any, resource any)

ReplyResourceCreated is a shortcut to handle 201/Created response. It sets status code to http.StatusCreated and adds proper `Location` header to response headers.

func RequireBearerToken

func RequireBearerToken(ctx *gin.Context) string

RequireBearerToken returns previously extracted "Bearer" token from the request context. Note this function can only be called after AuthBearerAPI middleware in the request handler call-chain.

func RequireManifest

func RequireManifest(ctx *gin.Context) manifest.ResourceManifest

RequireManifest returns manifest.ResourceManifest instance parsed out of request body by ManifestAPI middleware. Note: ManifestAPI middleware must be setup in the call chain before this call.

func RequireResourceID

func RequireResourceID(ctx *gin.Context) manifest.ResourceID

RequireResourceID return manifest.ResourceID previously extracted by ResourceAPI middleware, containing ID of the requested resource from the path. Note: must be used from a request handler that follows ResourceAPI middleware in the call chain.

func RequireSearchQuery

func RequireSearchQuery(ctx *gin.Context) manifest.SearchQuery

RequireSearchQuery returns manifest.SearchQuery from the call context previously set by SearchableAPI middleware in the call chain. Note, the function should only be called from a handler that follows after SearchableAPI middleware in the filter chain.

func RequireVersionedResource

func RequireVersionedResource(ctx *gin.Context) manifest.VersionedResourceID

RequireVersionedResource is a helper function to extract manifest.VersionedResourceID from the call context. Note, it must be called only from a handler that follows after VersionedResourceAPI middleware in the call-chain.

func ResourceAPI

func ResourceAPI() gin.HandlerFunc

ResourceAPI return a middleware to add support for parsing of resource IDs from request path. See RequireResourceID about how to access ResourceRequest containing passed resource ID.

func SearchableAPI

func SearchableAPI(defaultPaginationLimit uint) gin.HandlerFunc

SearchableAPI return middleware to support for [SearchQuery] parameter. See RequireSearchQuery usage on how to obtain [SearchQuery] value in the request handler

func VersionedResourceAPI

func VersionedResourceAPI() gin.HandlerFunc

VersionedResourceAPI returns middleware that reads Resource ID and Version query parameter in the request URL. See RequireVersionedResource and RequireVersionedResourceQuery for information on how to extract [VersionedResourceID] from the call context.

Types

type CreatedResponse

type CreatedResponse struct {
	// Gives us kind info
	manifest.TypeMeta `json:",inline" yaml:",inline"`

	// Id and version information of the newly created resource
	manifest.VersionedResourceID `json:",inline" yaml:",inline"`

	// Semantic actions
	HResponse `form:",inline" json:",inline" yaml:",inline"`
}

CreatedResponse represents information about newly created resource that is returned in response to 'Create' call.

type ErrorResponse

type ErrorResponse struct {
	// Error code represents error ID from a relevant domain
	Code int

	// Human readable representation of the error, suitable for display
	Message string

	HResponse `form:",inline" json:",inline" yaml:",inline"`
}

ErrorResponse represents a single error response with human readable reason and a code.

func NewErrorResponse

func NewErrorResponse(statusCode int, err error, options ...HResponseOption) (result *ErrorResponse)

NewErrorResponse return new ErrorResponse object built from an object implementing [error] interface. The constructor returns nil if err argument is nil and no other options passed.

func (*ErrorResponse) Error

func (e *ErrorResponse) Error() string

Error returns string representation of the error to implement error interface for ErrorResponse type.

type HLink struct {
	Reference    string `form:"ref" json:"ref" yaml:"ref" xml:"ref"`
	Relationship string `form:"rel" json:"rel" yaml:"rel" xml:"rel"`
}

HLink is a struct to hold semantic web links, representing action that can be performed on response item

type HResponse

type HResponse struct {
	Links map[string]HLink `form:"_links" json:"_links,omitempty" yaml:"_links,omitempty" xml:"_links"`
}

HResponse is a response object, produced by a server that has semantic references

type HResponseOption

type HResponseOption func(r *HResponse)

HResponseOption defines a type of 'optional' function that modifies HResponse properties when a new HResponse is constructed

func WithLink(role string, link HLink) HResponseOption

WithLink returns an HResponseOption option that adds a HATEOAS link to a response object

type PaginatedResponse

type PaginatedResponse[T any] struct {
	Count int `form:"count" json:"count,omitempty" yaml:"count,omitempty" xml:"count"`
	Data  []T `form:"data" json:"data,omitempty" yaml:"data,omitempty" xml:"data"`

	HResponse  `form:",inline" json:",inline" yaml:",inline"`
	Pagination `form:",inline" json:",inline" yaml:",inline"`
}

PaginatedResponse represents common frame used to produce response that returns a collection of results

func NewPaginatedResponse added in v0.1.2

func NewPaginatedResponse[T any](items []T, pInfo Pagination, options ...HResponseOption) PaginatedResponse[T]

NewPaginatedResponse creates a new paginated response with options to adjust HATEOAS response params

type Pagination

type Pagination struct {
	Page     uint `uri:"page" form:"page" json:"page,omitempty" yaml:"page,omitempty" xml:"page"`
	PageSize uint `uri:"pageSize" form:"pageSize" json:"pageSize,omitempty" yaml:"pageSize,omitempty" xml:"pageSize"`
}

Pagination is a set of common pagination query params

func (Pagination) ClampLimit

func (p Pagination) ClampLimit(maxLimit uint) Pagination

ClampLimit returns new pagination object that has its Pagination.Limit clamped to a value in between [0, maxLimit] range. If current value of of Pagination.Limit is within the [0, maxLimit] range then the value is unchanged, if the value of Pagination.Limit is outside of [0, maxLimit] range, maxLimit is used.

func (Pagination) Limit

func (p Pagination) Limit() uint

Limit returns maximum number of items that a query should return. Default value of 0 means that a client haven't specified a limit and the server will use default value.

func (Pagination) Offset

func (p Pagination) Offset() uint

Offset returns a 0-based index if a pagination was continues.

type ResourceRequest

type ResourceRequest struct {
	ID manifest.ResourceID `uri:"id" form:"id" binding:"required"`
}

ResourceRequest represents information to identify a single resource being referred in the path / query

type SearchParams added in v0.1.1

type SearchParams struct {
	Pagination `uri:",inline" form:",inline" json:",inline" yaml:",inline"`
	Timerange  `uri:",inline" form:",inline" json:",inline" yaml:",inline"`

	// Name is a fuzzy matched name of the resource to search for.
	Name string `uri:"name" form:"name" json:"name,omitempty" yaml:"name,omitempty" xml:"name"`

	// Filter label-based filter to narrow down results.
	Filter string `uri:"labels" form:"labels" json:"labels,omitempty" yaml:"labels,omitempty" xml:"labels"`
}

SearchParams represents grouping of query parameters commonly used by REST endpoint supporting search

func RequireSearchQueryParams added in v0.1.6

func RequireSearchQueryParams(ctx *gin.Context) SearchParams

RequireSearchQueryParams returns SearchParams from the call context previously set by SearchableAPI middleware in the call chain. Note, the function should only be called from a handler that follows after SearchableAPI middleware in the filter chain.

func (SearchParams) BuildQuery added in v0.1.1

func (s SearchParams) BuildQuery(defaultLimit uint) (manifest.SearchQuery, error)

BuildQuery returns a manifest.SearchQuery query object if the SearchParams can be converted to it.

type StatusResponse added in v0.1.10

type StatusResponse struct {
	Ready bool `form:"ready" json:"ready,omitempty" yaml:"ready,omitempty" xml:"ready"`
}

StatusResponse represents ready state / healthcheck response

type Timerange added in v0.1.8

type Timerange struct {
	// FromTime represents start of a time-range when searching for resources with time aspect.
	FromTime string `uri:"from" form:"from" json:"from,omitempty" yaml:"from,omitempty" xml:"from"`
	// TillTime represents end of a time-range when searching for resources with time aspect.
	TillTime string `uri:"till" form:"till" json:"till,omitempty" yaml:"till,omitempty" xml:"till"`
}

Common domain-agnostic types used to create rich REST APIs

type VersionQuery

type VersionQuery struct {
	Version manifest.Version `uri:"version" form:"version" binding:"required"`
}

VersionQuery is a set of query params for the versioned resource, such as specific version number of the resource in questions

func RequireVersionedResourceQuery added in v0.1.1

func RequireVersionedResourceQuery(ctx *gin.Context) VersionQuery

RequireVersionedResourceQuery is a helper function to extract VersionQuery from the call context. Note, it must be called only from a handler that follows after VersionedResourceAPI middleware in the call-chain.

type VersionResponse added in v0.1.10

type VersionResponse struct {
	Version   string `form:"version" json:"version,omitempty" yaml:"version,omitempty" xml:"version"`
	GoVersion string `form:"goVersion" json:"goVersion,omitempty" yaml:"goVersion,omitempty" xml:"goVersion"`
}

VersionResponse is a standard response object for /version request to inspect server running version.

func NewVersionResponse added in v0.1.10

func NewVersionResponse() VersionResponse

Jump to

Keyboard shortcuts

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