webgear-core-1.3.1: Composable, type-safe library to build HTTP APIs
Safe HaskellSafe-Inferred
LanguageHaskell2010

WebGear.Core.Trait

Description

Traits are optional attributes associated with a value. For example, a list containing totally ordered values might have a Maximum trait where the associated attribute is the maximum value. This trait exists only if the list is non-empty.

Traits help to associate attributes with values in a type-safe manner. WebGear associates traits with Requests and Responses to ensure certian attributes are present in them and access those with safety.

Traits are somewhat similar to refinement types, but allow arbitrary attributes to be associated with a value instead of only a predicate.

A value a associated with traits ts is referred to as a witnessed value, represented by the type a `With` ts where ts is a type-level list. You can extract a trait attribute from a witnessed value with:

pick @t (from witnessedValue)

The above expression will result in a compile-time error if t is not present in the type-level list of the witnessed value's type.

You can create a witnessed value in a number of ways:

First, you can use wzero to lift a regular value to a witnessed value with no associated traits.

Second, you can use probe to search for the presence of a trait and add it to the witnessed value; this will adjust the type-level list accordingly. This is used in cases where the regular value already contains the trait attribute which can be extracted using the Get typeclass.

Third, you can use plant to add a trait attribute to a witnessed value, thereby extending its type-level list with one more trait. This is used in cases where you want to modify the witnessed value. This operation requires an implementation of the Set typeclass.

Synopsis

Core Types

type family Attribute t a :: Type Source #

Type of the associated attribute when the trait t holds for a value a.

Instances

Instances details
type Attribute UnknownContentBody Response Source # 
Instance details

Defined in WebGear.Core.Trait.Body

type Attribute Method Request Source # 
Instance details

Defined in WebGear.Core.Trait.Method

type Attribute Path Request Source # 
Instance details

Defined in WebGear.Core.Trait.Path

type Attribute PathEnd Request Source # 
Instance details

Defined in WebGear.Core.Trait.Path

type Attribute Status Response Source # 
Instance details

Defined in WebGear.Core.Trait.Status

type Attribute (Body mt t) Request Source # 
Instance details

Defined in WebGear.Core.Trait.Body

type Attribute (Body mt t) Request = t
type Attribute (Body mt t) Response Source # 
Instance details

Defined in WebGear.Core.Trait.Body

type Attribute (Body mt t) Response = t
type Attribute (SetCookie 'Optional name) Response Source # 
Instance details

Defined in WebGear.Core.Trait.Cookie

type Attribute (SetCookie 'Required name) Response Source # 
Instance details

Defined in WebGear.Core.Trait.Cookie

type Attribute (PathVar tag val) Request Source # 
Instance details

Defined in WebGear.Core.Trait.Path

type Attribute (PathVar tag val) Request = val
type Attribute (Cookie 'Optional name val) Request Source # 
Instance details

Defined in WebGear.Core.Trait.Cookie

type Attribute (Cookie 'Optional name val) Request = Maybe val
type Attribute (Cookie 'Required name val) Request Source # 
Instance details

Defined in WebGear.Core.Trait.Cookie

type Attribute (Cookie 'Required name val) Request = val
type Attribute (ResponseHeader 'Optional name val) Response Source # 
Instance details

Defined in WebGear.Core.Trait.Header

type Attribute (ResponseHeader 'Required name val) Response Source # 
Instance details

Defined in WebGear.Core.Trait.Header

type Attribute (ResponseHeader 'Required name val) Response = val
type Attribute (RequestHeader 'Optional 'Lenient name val) Request Source # 
Instance details

Defined in WebGear.Core.Trait.Header

type Attribute (RequestHeader 'Optional 'Strict name val) Request Source # 
Instance details

Defined in WebGear.Core.Trait.Header

type Attribute (RequestHeader 'Required 'Lenient name val) Request Source # 
Instance details

Defined in WebGear.Core.Trait.Header

type Attribute (RequestHeader 'Required 'Strict name val) Request Source # 
Instance details

Defined in WebGear.Core.Trait.Header

type Attribute (QueryParam 'Optional 'Lenient name val) Request Source # 
Instance details

Defined in WebGear.Core.Trait.QueryParam

type Attribute (QueryParam 'Optional 'Strict name val) Request Source # 
Instance details

Defined in WebGear.Core.Trait.QueryParam

type Attribute (QueryParam 'Required 'Lenient name val) Request Source # 
Instance details

Defined in WebGear.Core.Trait.QueryParam

type Attribute (QueryParam 'Required 'Strict name val) Request Source # 
Instance details

Defined in WebGear.Core.Trait.QueryParam

type Attribute (QueryParam 'Required 'Strict name val) Request = val
type Attribute (BasicAuth' 'Optional scheme m e a) Request Source # 
Instance details

Defined in WebGear.Core.Trait.Auth.Basic

type Attribute (BasicAuth' 'Required scheme m e a) Request Source # 
Instance details

Defined in WebGear.Core.Trait.Auth.Basic

type Attribute (BasicAuth' 'Required scheme m e a) Request = a
type Attribute (JWTAuth' 'Optional scheme m e a) Request Source # 
Instance details

Defined in WebGear.Core.Trait.Auth.JWT

type Attribute (JWTAuth' 'Optional scheme m e a) Request = Either (JWTAuthError e) a
type Attribute (JWTAuth' 'Required scheme m e a) Request Source # 
Instance details

Defined in WebGear.Core.Trait.Auth.JWT

type Attribute (JWTAuth' 'Required scheme m e a) Request = a

type family Absence t :: Type Source #

Type that indicates that the trait does not exist on a request. This could be an error message, exception etc.

Instances

Instances details
type Absence Method Source # 
Instance details

Defined in WebGear.Core.Trait.Method

type Absence Path Source # 
Instance details

Defined in WebGear.Core.Trait.Path

type Absence Path = ()
type Absence PathEnd Source # 
Instance details

Defined in WebGear.Core.Trait.Path

type Absence PathEnd = ()
type Absence (Body mt t) Source # 
Instance details

Defined in WebGear.Core.Trait.Body

type Absence (Body mt t) = Text
type Absence (PathVar tag val) Source # 
Instance details

Defined in WebGear.Core.Trait.Path

type Absence (PathVar tag val) = PathVarError
type Absence (Cookie 'Optional name val) Source # 
Instance details

Defined in WebGear.Core.Trait.Cookie

type Absence (Cookie 'Required name val) Source # 
Instance details

Defined in WebGear.Core.Trait.Cookie

type Absence (RequestHeader 'Optional 'Lenient name val) Source # 
Instance details

Defined in WebGear.Core.Trait.Header

type Absence (RequestHeader 'Optional 'Strict name val) Source # 
Instance details

Defined in WebGear.Core.Trait.Header

type Absence (RequestHeader 'Required 'Lenient name val) Source # 
Instance details

Defined in WebGear.Core.Trait.Header

type Absence (RequestHeader 'Required 'Strict name val) Source # 
Instance details

Defined in WebGear.Core.Trait.Header

type Absence (QueryParam 'Optional 'Lenient name val) Source # 
Instance details

Defined in WebGear.Core.Trait.QueryParam

type Absence (QueryParam 'Optional 'Lenient name val) = Void
type Absence (QueryParam 'Optional 'Strict name val) Source # 
Instance details

Defined in WebGear.Core.Trait.QueryParam

type Absence (QueryParam 'Required 'Lenient name val) Source # 
Instance details

Defined in WebGear.Core.Trait.QueryParam

type Absence (QueryParam 'Required 'Strict name val) Source # 
Instance details

Defined in WebGear.Core.Trait.QueryParam

type Absence (BasicAuth' 'Optional scheme m e a) Source # 
Instance details

Defined in WebGear.Core.Trait.Auth.Basic

type Absence (BasicAuth' 'Optional scheme m e a) = Void
type Absence (BasicAuth' 'Required scheme m e a) Source # 
Instance details

Defined in WebGear.Core.Trait.Auth.Basic

type Absence (BasicAuth' 'Required scheme m e a) = BasicAuthError e
type Absence (JWTAuth' 'Optional scheme m e a) Source # 
Instance details

Defined in WebGear.Core.Trait.Auth.JWT

type Absence (JWTAuth' 'Optional scheme m e a) = Void
type Absence (JWTAuth' 'Required scheme m e a) Source # 
Instance details

Defined in WebGear.Core.Trait.Auth.JWT

type Absence (JWTAuth' 'Required scheme m e a) = JWTAuthError e

type family Prerequisite (t :: Type) (ts :: [Type]) :: Constraint Source #

Indicates the constraints a trait depends upon as a prerequisite. This is used to assert that a trait t can be extracted from a request only if one or more other traits are present in the trait list ts associated with it.

If a trait does not depend on other traits this can be set to the empty contraint ().

Instances

Instances details
type Prerequisite Method ts Source # 
Instance details

Defined in WebGear.Core.Trait.Method

type Prerequisite Method ts = ()
type Prerequisite Path ts Source # 
Instance details

Defined in WebGear.Core.Trait.Path

type Prerequisite Path ts = ()
type Prerequisite PathEnd ts Source # 
Instance details

Defined in WebGear.Core.Trait.Path

type Prerequisite PathEnd ts = ()
type Prerequisite (Body mt t) ts Source # 
Instance details

Defined in WebGear.Core.Trait.Body

type Prerequisite (Body mt t) ts = ()
type Prerequisite (PathVar tag val) ts Source # 
Instance details

Defined in WebGear.Core.Trait.Path

type Prerequisite (PathVar tag val) ts = ()
type Prerequisite (Cookie e name val) ts Source # 
Instance details

Defined in WebGear.Core.Trait.Cookie

type Prerequisite (Cookie e name val) ts = HasTrait (RequestHeader e 'Strict "Cookie" Text) ts
type Prerequisite (RequestHeader e p name val) ts Source # 
Instance details

Defined in WebGear.Core.Trait.Header

type Prerequisite (RequestHeader e p name val) ts = ()
type Prerequisite (QueryParam e p name val) ts Source # 
Instance details

Defined in WebGear.Core.Trait.QueryParam

type Prerequisite (QueryParam e p name val) ts = ()
type Prerequisite (BasicAuth' x scheme m e a) ts Source # 
Instance details

Defined in WebGear.Core.Trait.Auth.Basic

type Prerequisite (BasicAuth' x scheme m e a) ts = HasTrait (AuthorizationHeader scheme) ts
type Prerequisite (JWTAuth' x scheme m e a) ts Source # 
Instance details

Defined in WebGear.Core.Trait.Auth.JWT

type Prerequisite (JWTAuth' x scheme m e a) ts = HasTrait (AuthorizationHeader scheme) ts

class Arrow h => Get h t where Source #

Extract trait attributes from a request.

Methods

getTrait Source #

Arguments

:: Prerequisite t ts 
=> t

The trait to witness

-> h (Request `With` ts) (Either (Absence t) (Attribute t Request))

Arrow that attemtps to witness the trait and can possibly fail

Attempt to witness the trait attribute from the request.

type family Gets h ts :: Constraint where ... Source #

Gets h ts is equivalent to (Get h t1, Get h t2, ..., Get h tn) where ts = [t1, t2, ..., tn].

Equations

Gets h '[] = () 
Gets h (t : ts) = (Get h t, Gets h ts) 

class Arrow h => Set h (t :: Type) where Source #

Associate a trait attribute on a response

Methods

setTrait Source #

Arguments

:: t

The trait to set

-> ((Response `With` ts) -> Response -> Attribute t Response -> Response `With` (t : ts))

A function to generate a witnessed response. This function must be called by the setTrait implementation to generate a witnessed response.

-> h (Response `With` ts, Attribute t Response) (Response `With` (t : ts))

An arrow that attaches a new trait attribute to a witnessed value.

Set a trait attribute t on the value Response `With` ts.

type family Sets h ts :: Constraint where ... Source #

Sets h ts is equivalent to (Set h t1, Set h t2, ..., Set h tn) where ts = [t1, t2, ..., tn].

Equations

Sets h '[] = () 
Sets h (t : ts) = (Set h t, Sets h ts) 

data With a (ts :: [Type]) Source #

A value associated with a list of traits, referred to as a witnessed value. Typically, this is used as an infix type constructor:

a `With` ts

where a is a value and ts is a list of traits associated with that value.

If t is a type present in the list of types ts, it is possible to extract its attribute from a witnessed value:

let witnessedValue :: a `With` ts
    witnessedValue = ...

let attr :: Attribute t a
    attr = pick @t (from witnessedValue)

Associating values with attributes

wzero :: a -> a `With` '[] Source #

Lift a value to a witnessed value having no associated traits.

wminus :: (a `With` (t : ts)) -> a `With` ts Source #

Forget the head trait

unwitness :: With a ts -> a Source #

Retrieve the value

probe :: forall t ts h. (Get h t, Prerequisite t ts) => t -> h (Request `With` ts) (Either (Absence t) (Request `With` (t : ts))) Source #

Attempt to witness an additional trait with a witnessed request. This can fail indicating an Absence of the trait.

plant :: forall t ts h. Set h t => t -> h (Response `With` ts, Attribute t Response) (Response `With` (t : ts)) Source #

Set a trait attribute on witnessed response to produce another witnessed response with the additional trait attached to it.

Retrieve trait attributes from witnessed values

class HasTrait t ts where Source #

Constraint that proves that the trait t is present in the list of traits ts.

Methods

from :: (a `With` ts) -> Tagged t (Attribute t a) Source #

Get the attribute associated with t from a witnessed value. See also: pick.

Instances

Instances details
(TypeError (MissingTrait t) :: Constraint) => HasTrait t ('[] :: [Type]) Source # 
Instance details

Defined in WebGear.Core.Trait

Methods

from :: With a '[] -> Tagged t (Attribute t a) Source #

HasTrait t (t ': ts) Source # 
Instance details

Defined in WebGear.Core.Trait

Methods

from :: With a (t ': ts) -> Tagged t (Attribute t a) Source #

HasTrait t ts => HasTrait t (t' ': ts) Source # 
Instance details

Defined in WebGear.Core.Trait

Methods

from :: With a (t' ': ts) -> Tagged t (Attribute t a) Source #

type family HaveTraits ts qs :: Constraint where ... Source #

Constraint that proves that all the traits in the list ts are also present in the list qs.

Equations

HaveTraits '[] qs = () 
HaveTraits (t : ts) qs = (HasTrait t qs, HaveTraits ts qs) 

pick :: Tagged t a -> a Source #

Retrieve a trait.

pick is used along with from to retrieve an attribute from a witnessed value:

pick @t (from val)

type MissingTrait t = ((((((((Text "The value doesn't have the \8216" :<>: ShowType t) :<>: Text "\8217 trait.") :$$: Text "") :$$: Text "Did you forget to apply an appropriate middleware?") :$$: Text "For e.g. The trait \8216Body JSON t\8217 requires \8216requestBody @t JSON\8217 middleware.") :$$: Text "") :$$: Text "or did you use a wrong trait type?") :$$: Text "For e.g., \8216RequiredQueryParam \"foo\" Int\8217 instead of \8216RequiredQueryParam \"foo\" String\8217?") :$$: Text "" Source #

Type error for nicer UX of missing traits