Documentation ¶
Overview ¶
Package gouldian is Go combinator library for building HTTP services. The library is a thin layer of purely functional abstractions to building simple and declarative api implementations in the absence of pattern matching for traditional and serverless applications.
Inspiration ¶
The library is heavily inspired by Scala Finch https://github.com/finagle/finch.
Getting started ¶
Here is minimal "Hello World!" example that matches any HTTP requests to /hello endpoint.
package main import ( µ "github.com/fogfish/gouldian" "github.com/fogfish/gouldian/server/httpd" "net/http" ) func main() { http.ListenAndServe(":8080", httpd.Serve(hello()), ) } func hello() µ.Endpoint { return µ.GET( µ.URI(µ.Path("hello")), func(ctx µ.Context) error { return µ.Status.OK(µ.WithText("Hello World!")) }, ) }
See examples folder for advanced use-case.
Next steps ¶
↣ Study Endpoint type and its composition, see User Guide
↣ Check build-in collection of endpoints to deal with HTTP request. See types: HTTP, APIGateway
↣ Endpoint always returns some `Output` that defines HTTP response. There are three cases of output: HTTP Success, HTTP Failure and general error. See Output, Issue types.
Index ¶
- Constants
- Variables
- func FromContext[S any](ctx *Context, val *S) error
- func Optics2[T, A, B any](attr ...string) (Lens, Lens)
- func Optics3[T, A, B, C any](attr ...string) (Lens, Lens, Lens)
- func Optics4[T, A, B, C, D any](attr ...string) (Lens, Lens, Lens, Lens)
- func Optics5[T, A, B, C, D, E any](attr ...string) (Lens, Lens, Lens, Lens, Lens)
- func Optics6[T, A, B, C, D, E, F any](attr ...string) (Lens, Lens, Lens, Lens, Lens, Lens)
- func Optics7[T, A, B, C, D, E, F, G any](attr ...string) (Lens, Lens, Lens, Lens, Lens, Lens, Lens)
- func Optics8[T, A, B, C, D, E, F, G, H any](attr ...string) (Lens, Lens, Lens, Lens, Lens, Lens, Lens, Lens)
- func Optics9[T, A, B, C, D, E, F, G, H, I any](attr ...string) (Lens, Lens, Lens, Lens, Lens, Lens, Lens, Lens, Lens)
- type Context
- type Endpoint
- func Authorization(f func(string, string) error) Endpoint
- func Body(lens Lens) Endpoint
- func FMap[A any](f func(*Context, *A) error) Endpoint
- func Header[T Pattern](hdr string, val T) Endpoint
- func HeaderAny(hdr string) Endpoint
- func HeaderMaybe(header string, lens Lens) Endpoint
- func JWT[T Pattern](claim JWTClaim, val T) Endpoint
- func JWTAllOf(claim JWTClaim, vals ...string) Endpoint
- func JWTMaybe(claim JWTClaim, lens optics.Lens) Endpoint
- func JWTOneOf(claim JWTClaim, vals ...string) Endpoint
- func Join(seq ...Endpoint) Endpoint
- func Map[A, B any](f func(*Context, *A) (*B, error)) Endpoint
- func Method(verb string) Endpoint
- func Or(seq ...Endpoint) Endpoint
- func Param[T Pattern](key string, val T) Endpoint
- func ParamAny(key string) Endpoint
- func ParamJSON(key string, lens Lens) Endpoint
- func ParamMaybe(key string, lens Lens) Endpoint
- func ParamMaybeJSON(key string, lens Lens) Endpoint
- type Endpoints
- type Issue
- type JWTClaim
- type Lens
- type NoMatch
- type Node
- type Output
- type Params
- type Pattern
- type Result
- type Routable
- func ANY(path Routable, arrows ...Endpoint) Routable
- func DELETE(path Routable, arrows ...Endpoint) Routable
- func GET(path Routable, arrows ...Endpoint) Routable
- func PATCH(path Routable, arrows ...Endpoint) Routable
- func POST(path Routable, arrows ...Endpoint) Routable
- func PUT(path Routable, arrows ...Endpoint) Routable
- func Route(path Routable, seq ...Endpoint) Routable
- func URI(segments ...Segment) Routable
- type Router
- type Segment
- type StatusCode
- func (code StatusCode) Accepted(out ...Result) error
- func (code StatusCode) BadGateway(out ...Result) error
- func (code StatusCode) BadRequest(out ...Result) error
- func (code StatusCode) Conflict(out ...Result) error
- func (code StatusCode) Created(out ...Result) error
- func (code StatusCode) Forbidden(out ...Result) error
- func (code StatusCode) Found(out ...Result) error
- func (code StatusCode) GatewayTimeout(out ...Result) error
- func (code StatusCode) Gone(out ...Result) error
- func (code StatusCode) HTTPVersionNotSupported(out ...Result) error
- func (code StatusCode) InternalServerError(out ...Result) error
- func (code StatusCode) LengthRequired(out ...Result) error
- func (code StatusCode) MethodNotAllowed(out ...Result) error
- func (code StatusCode) MovedPermanently(out ...Result) error
- func (code StatusCode) MultipleChoices(out ...Result) error
- func (code StatusCode) NoContent(out ...Result) error
- func (code StatusCode) NonAuthoritativeInfo(out ...Result) error
- func (code StatusCode) NotAcceptable(out ...Result) error
- func (code StatusCode) NotFound(out ...Result) error
- func (code StatusCode) NotImplemented(out ...Result) error
- func (code StatusCode) NotModified(out ...Result) error
- func (code StatusCode) OK(out ...Result) error
- func (code StatusCode) PaymentRequired(out ...Result) error
- func (code StatusCode) PermanentRedirect(out ...Result) error
- func (code StatusCode) PreconditionFailed(out ...Result) error
- func (code StatusCode) ProxyAuthRequired(out ...Result) error
- func (code StatusCode) RequestEntityTooLarge(out ...Result) error
- func (code StatusCode) RequestTimeout(out ...Result) error
- func (code StatusCode) RequestURITooLong(out ...Result) error
- func (code StatusCode) ResetContent(out ...Result) error
- func (code StatusCode) SeeOther(out ...Result) error
- func (code StatusCode) ServiceUnavailable(out ...Result) error
- func (code StatusCode) TemporaryRedirect(out ...Result) error
- func (code StatusCode) Unauthorized(out ...Result) error
- func (code StatusCode) UnsupportedMediaType(out ...Result) error
- func (code StatusCode) UseProxy(out ...Result) error
- type Token
Constants ¶
const (
// Any constant matches any term
Any = "_"
)
const Status = StatusCode(0)
Status is collection of constants for HTTP Status Code
return µ.Status.Ok()
Variables ¶
var ErrNoMatch error = NoMatch(255)
ErrNoMatch constant
Functions ¶
func FromContext ¶ added in v1.6.0
Get decodes context into structure
Types ¶
type Context ¶ added in v1.2.0
type Context struct { context.Context Request *http.Request JWT Token // contains filtered or unexported fields }
Context of HTTP request. The context accumulates matched terms of HTTP and passes it to destination function.
func NewContext ¶ added in v1.2.0
NewContext create a new context for HTTP request
type Endpoint ¶
Endpoint is a composable function that abstract HTTP endpoint. The function takes HTTP request and returns value of some type: `Context => Output`.
↣ `Context` is a wrapper over HTTP request with additional context.
↣ `Output` is sum type that represents if it is matched on a given input or not. The library uses `error` type to represent both valid and invalid variants.
Any `Endpoint A` can be composed with `Endpoint B` into new `Endpoint C`. It supports two combinators: and-then, or-else.
↣ Use `and-then` to build product Endpoint. The product type matches Input if each composed function successfully matches it.
↣ Use `or-else` to build co-product Endpoint. The co-product is also known as sum-type matches first successful function.
Endpoint life-cycle - each incoming HTTP request is wrapped with `Input` and applied to an endpoint. A returned error-like results is checked against successful Output or NoMatch error. All these machinery is handled by the libray, you should only dare to declare Endpoint from ready made primitives.
gouldian library delivers set of built-in endpoints to deal with HTTP request processing.
func Authorization ¶ added in v1.6.0
Authorization defines Endpoints that simplify validation of credentials/tokens supplied within the request
e := µ.GET( µ.Authorization(func(string, string) error { ... }) ) e(mock.Input(mock.Header("Authorization", "Basic foo"))) == nil e(mock.Input(mock.Header("Authorization", "Basic bar"))) != nil
func FMap ¶
FMap applies clojure to matched HTTP request, taking the execution context as the input to closure
func Header ¶
Header combinator defines primitives to match Headers of HTTP requests.
endpoint := µ.GET( µ.Header("X-Foo", "Bar"), ) endpoint( mock.Input( mock.Header("X-Foo", "Bar") ) ) == nil
func HeaderAny ¶ added in v1.6.0
HeaderAny is a wildcard matcher of header. It fails if header is not defined.
e := µ.GET( µ.HeaderAny("X-Foo") ) e(mock.Input(mock.Header("X-Foo", "Bar"))) == nil e(mock.Input(mock.Header("X-Foo", "Baz"))) == nil e(mock.Input()) != nil
func HeaderMaybe ¶ added in v1.6.0
HeaderMaybe matches header value to the request context. It uses lens abstraction to decode HTTP header into Golang type. The Endpoint does not cause no-match if header value cannot be decoded to the target type. See optics.Lens type for details.
type myT struct{ Val string } x := µ.Optics1[myT, string]() e := µ.GET(µ.HeaderMaybe("X-Foo", x)) e(mock.Input(mock.Header("X-Foo", "Bar"))) == nil
func JWT ¶
JWT combinator defines primitives to match JWT token in the HTTP requests.
endpoint := µ.GET( µ.JWT(µ.Token.Username, "joedoe"), ) endpoint( mock.Input( mock.JWT(µ.Token{"username": "joedoe"}) ) ) == nil
func JWTAllOf ¶ added in v1.6.0
JWTAllOf matches a key of JWT if it contains one of the tokens
µ.GET( µ.JWTAllOf(µ.JWT.Scope, "ro", "rw") )
func JWTMaybe ¶ added in v1.6.0
JWTMaybe matches key of JWT to the request context. It uses lens abstraction to decode value into Golang type. The Endpoint does not cause no-match if header value cannot be decoded to the target type. See optics.Lens type for details.
type MyT struct{ Username string } username := µ.Optics1[MyT, string]() e := µ.GET( µ.JWTMaybe(µ.JWT.Sub).Maybe(username) ) e(mock.Input(mock.JWT(µ.JWT{"username": "joedoe"}))) == nil
func JWTOneOf ¶ added in v1.6.0
JWTOneOf matches a key of JWT if it contains one of the tokens
µ.GET( µ.JWTOneOf(µ.JWT.Scope, "ro", "rw") )
func Map ¶ added in v1.6.0
Map applies clojure to matched HTTP request, taking the execution context and matched parameters as the input to closure. The output is always returned as JSON.
func Param ¶
Param combinator defines primitives to match query param in the HTTP requests.
endpoint := µ.GET( µ.Param("foo", "bar"), ) endpoint( mock.Input( mock.URL("/?foo=bar") ) ) == nil
func ParamAny ¶ added in v1.6.0
ParamAny is a wildcard matcher of param key. It fails if key is not defined.
e := µ.GET( µ.ParamAny("foo") ) e(mock.Input(mock.URL("/?foo"))) == nil e(mock.Input(mock.URL("/?foo=bar"))) == nil e(mock.Input(mock.URL("/?foo=baz"))) == nil e(mock.Input()) != nil
func ParamJSON ¶ added in v1.6.0
JSON matches a param key to struct. It assumes that key holds JSON value as url encoded string
func ParamMaybe ¶ added in v1.6.0
ParamMaybe matches param value to the request context. It uses lens abstraction to decode value into Golang type. The Endpoint does not cause no-match if header value cannot be decoded to the target type. See optics.Lens type for details.
type myT struct{ Val string } x := µ.Optics1[myT, string]() e := µ.GET( µ.ParamMaybe("foo", x) ) e(mock.Input(mock.URL("/?foo=bar"))) == nil e(mock.Input(mock.URL("/?foo"))) == nil e(mock.Input(mock.URL("/"))) == nil
func ParamMaybeJSON ¶ added in v1.6.0
MaybeJSON matches a param key to closed struct. It assumes that key holds JSON value as url encoded string. It does not fail if key is not defined.
type Endpoints ¶ added in v1.4.0
type Endpoints []Endpoint
Endpoints is sequence of Endpoints
type Issue ¶
type Issue struct { ID string `json:"instance"` Type string `json:"type"` Status int `json:"status"` Title string `json:"title"` }
Issue implements RFC 7807: Problem Details for HTTP APIs
type Node ¶ added in v1.4.0
type Node struct { Path string // substring from the route "owned" by the node Heir []*Node // heir nodes Func Endpoint // end point associated with node }
Node of trie
type Output ¶
type Output struct { Status int Headers []struct{ Header, Value string } Body string Failure error }
Output is HTTP response
type Result ¶ added in v1.2.0
Result is a composable function that abstract results of HTTP endpoint. The function takes instance of HTTP output and mutates its value
return µ.Status.OK( µ.WithHeader(headers.ContentType, headers.ApplicationJson), µ.WithJSON(value), )
func WithBytes ¶ added in v1.2.0
WithBytes appends arbitrary octet/stream payload to HTTP response content type shall be specified using With method
func WithHeader ¶ added in v1.2.0
WithHeader appends header to HTTP response
type Routable ¶ added in v1.4.0
Routable is endpoint with routing metadata
func ANY ¶
ANY composes Endpoints into Routable that matches HTTP any request.
e := µ.ANY( µ.URI(µ.Path("foo"), µ.Path("bar")), ... ) e(mock.Input(mock.Method("PUT"))) == nil e(mock.Input(mock.Method("OTHER"))) == nil
func DELETE ¶
DELETE composes Endpoints into Routable that matches HTTP DELETE request.
e := µ.DELETE( µ.URI(µ.Path("foo"), µ.Path("bar")), ... ) e(mock.Input(mock.Method("DELETE"))) == nil e(mock.Input(mock.Method("OTHER"))) != nil
func GET ¶
GET composes Endpoints into Routable that matches HTTP GET request.
e := µ.GET( µ.URI(µ.Path("foo"), µ.Path("bar")), ... ) e(mock.Input(mock.Method("GET"))) == nil e(mock.Input(mock.Method("OTHER"))) != nil
func PATCH ¶
PATCH composes Endpoints into Routable that matches HTTP PATCH request.
e := µ.PATCH( µ.URI(µ.Path("foo"), µ.Path("bar")), ... ) e(mock.Input(mock.Method("PATCH"))) == nil e(mock.Input(mock.Method("OTHER"))) != nil
func POST ¶
POST composes Endpoints into Routable that matches HTTP POST request.
e := µ.POST( µ.URI(µ.Path("foo"), µ.Path("bar")), ... ) e(mock.Input(mock.Method("POST"))) == nil e(mock.Input(mock.Method("OTHER"))) != nil
func PUT ¶
PUT composes Endpoints into Routable that matches HTTP PUT request.
e := µ.PUT( µ.URI(µ.Path("foo"), µ.Path("bar")), ... ) e(mock.Input(mock.Method("PUT"))) == nil e(mock.Input(mock.Method("OTHER"))) != nil
func URI ¶ added in v1.6.0
URI is an endpoint to match URL of HTTP request. The function takes a sequence of segment patterns as input. These patterns are either literals or lenses, where each term corresponds to the path segment. The function do not match if length of path is not equal to the length of pattern or segment do not match to pattern
e := µ.GET( µ.URI(µ.Path("foo")) ) e(mock.Input(mock.URL("/foo"))) == nil e(mock.Input(mock.URL("/bar"))) != nil
type Router ¶ added in v1.4.0
type Router interface {
Endpoint() Endpoint
}
Router is data structure that holds routing information, convertable to Endpoint
type Segment ¶ added in v1.6.0
type Segment struct {
// contains filtered or unexported fields
}
Segment union type, make URI type safe
func Path ¶
Path is an endpoint to match a single URL segment of HTTP request. The function takes a path pattern as arguments. The pattern is either literal or lens. The function do not match if segment do not match to pattern
e := µ.GET( µ.URI(µ.Path("foo")) ) e(mock.Input(mock.URL("/foo"))) == nil e(mock.Input(mock.URL("/bar"))) != nil
type StatusCode ¶ added in v1.2.0
type StatusCode int
StatusCode is a warpper type over http.StatusCode so that ...
func (StatusCode) Accepted ¶ added in v1.2.0
func (code StatusCode) Accepted(out ...Result) error
Accepted ⟼ http.StatusAccepted
func (StatusCode) BadGateway ¶ added in v1.2.0
func (code StatusCode) BadGateway(out ...Result) error
BadGateway ⟼ http.StatusBadGateway
func (StatusCode) BadRequest ¶ added in v1.2.0
func (code StatusCode) BadRequest(out ...Result) error
BadRequest ⟼ http.StatusBadRequest
func (StatusCode) Conflict ¶ added in v1.2.0
func (code StatusCode) Conflict(out ...Result) error
Conflict ⟼ http.StatusConflict
func (StatusCode) Created ¶ added in v1.2.0
func (code StatusCode) Created(out ...Result) error
Created ⟼ http.StatusCreated
func (StatusCode) Forbidden ¶ added in v1.2.0
func (code StatusCode) Forbidden(out ...Result) error
Forbidden ⟼ http.StatusForbidden
func (StatusCode) Found ¶ added in v1.2.0
func (code StatusCode) Found(out ...Result) error
Found ⟼ http.StatusFound
func (StatusCode) GatewayTimeout ¶ added in v1.2.0
func (code StatusCode) GatewayTimeout(out ...Result) error
GatewayTimeout ⟼ http.StatusGatewayTimeout
func (StatusCode) Gone ¶ added in v1.2.0
func (code StatusCode) Gone(out ...Result) error
Gone ⟼ http.StatusGone
func (StatusCode) HTTPVersionNotSupported ¶ added in v1.2.0
func (code StatusCode) HTTPVersionNotSupported(out ...Result) error
HTTPVersionNotSupported ⟼ http.StatusHTTPVersionNotSupported
func (StatusCode) InternalServerError ¶ added in v1.2.0
func (code StatusCode) InternalServerError(out ...Result) error
InternalServerError ⟼ http.StatusInternalServerError
func (StatusCode) LengthRequired ¶ added in v1.2.0
func (code StatusCode) LengthRequired(out ...Result) error
LengthRequired ⟼ http.StatusLengthRequired
func (StatusCode) MethodNotAllowed ¶ added in v1.2.0
func (code StatusCode) MethodNotAllowed(out ...Result) error
MethodNotAllowed ⟼ http.StatusMethodNotAllowed
func (StatusCode) MovedPermanently ¶ added in v1.2.0
func (code StatusCode) MovedPermanently(out ...Result) error
MovedPermanently ⟼ http.StatusMovedPermanently
func (StatusCode) MultipleChoices ¶ added in v1.2.0
func (code StatusCode) MultipleChoices(out ...Result) error
MultipleChoices ⟼ http.StatusMultipleChoices
func (StatusCode) NoContent ¶ added in v1.2.0
func (code StatusCode) NoContent(out ...Result) error
NoContent ⟼ http.StatusNoContent
func (StatusCode) NonAuthoritativeInfo ¶ added in v1.2.0
func (code StatusCode) NonAuthoritativeInfo(out ...Result) error
NonAuthoritativeInfo ⟼ http.StatusNonAuthoritativeInfo
func (StatusCode) NotAcceptable ¶ added in v1.2.0
func (code StatusCode) NotAcceptable(out ...Result) error
NotAcceptable ⟼ http.StatusNotAcceptable
func (StatusCode) NotFound ¶ added in v1.2.0
func (code StatusCode) NotFound(out ...Result) error
NotFound ⟼ http.StatusNotFound
func (StatusCode) NotImplemented ¶ added in v1.2.0
func (code StatusCode) NotImplemented(out ...Result) error
NotImplemented ⟼ http.StatusNotImplemented
func (StatusCode) NotModified ¶ added in v1.2.0
func (code StatusCode) NotModified(out ...Result) error
NotModified ⟼ http.StatusNotModified
func (StatusCode) OK ¶ added in v1.2.0
func (code StatusCode) OK(out ...Result) error
OK ⟼ http.StatusOK
func (StatusCode) PaymentRequired ¶ added in v1.2.0
func (code StatusCode) PaymentRequired(out ...Result) error
PaymentRequired ⟼ http.StatusPaymentRequired
func (StatusCode) PermanentRedirect ¶ added in v1.2.0
func (code StatusCode) PermanentRedirect(out ...Result) error
PermanentRedirect ⟼ http.StatusPermanentRedirect
func (StatusCode) PreconditionFailed ¶ added in v1.2.0
func (code StatusCode) PreconditionFailed(out ...Result) error
PreconditionFailed ⟼ http.StatusPreconditionFailed
func (StatusCode) ProxyAuthRequired ¶ added in v1.2.0
func (code StatusCode) ProxyAuthRequired(out ...Result) error
ProxyAuthRequired ⟼ http.StatusProxyAuthRequired
func (StatusCode) RequestEntityTooLarge ¶ added in v1.2.0
func (code StatusCode) RequestEntityTooLarge(out ...Result) error
RequestEntityTooLarge ⟼ http.StatusRequestEntityTooLarge
func (StatusCode) RequestTimeout ¶ added in v1.2.0
func (code StatusCode) RequestTimeout(out ...Result) error
RequestTimeout ⟼ http.StatusRequestTimeout
func (StatusCode) RequestURITooLong ¶ added in v1.2.0
func (code StatusCode) RequestURITooLong(out ...Result) error
RequestURITooLong ⟼ http.StatusRequestURITooLong
func (StatusCode) ResetContent ¶ added in v1.2.0
func (code StatusCode) ResetContent(out ...Result) error
ResetContent ⟼ http.StatusResetContent
func (StatusCode) SeeOther ¶ added in v1.2.0
func (code StatusCode) SeeOther(out ...Result) error
SeeOther ⟼ http.StatusSeeOther
func (StatusCode) ServiceUnavailable ¶ added in v1.2.0
func (code StatusCode) ServiceUnavailable(out ...Result) error
ServiceUnavailable ⟼ http.StatusServiceUnavailable
func (StatusCode) TemporaryRedirect ¶ added in v1.2.0
func (code StatusCode) TemporaryRedirect(out ...Result) error
TemporaryRedirect ⟼ http.StatusTemporaryRedirect
func (StatusCode) Unauthorized ¶ added in v1.2.0
func (code StatusCode) Unauthorized(out ...Result) error
Unauthorized ⟼ http.StatusUnauthorized
func (StatusCode) UnsupportedMediaType ¶ added in v1.2.0
func (code StatusCode) UnsupportedMediaType(out ...Result) error
UnsupportedMediaType ⟼ http.StatusUnsupportedMediaType
func (StatusCode) UseProxy ¶ added in v1.2.0
func (code StatusCode) UseProxy(out ...Result) error
UseProxy ⟼ http.StatusUseProxy