trasa-0.1: Type Safe Web Routing

Safe HaskellNone
LanguageHaskell2010

Trasa.Tutorial

Contents

Description

Users of this library should a data type representing all possible routes available in a web application. It is recommended that this type be named Route, but this is not required.

Synopsis

Dispatch and Routing

In this example, we will write web application that maintains three counters. The end user will be able to perform various operations that manipulate the values of these counters and ask for their current value. We begin by defining our route type:

>>> :{
data Counter = Red | Green | Blue
  deriving (Show,Read)
data Route :: [Type] -> [Param] -> Bodiedness -> Type -> Type where
  AssignR :: Route '[Counter,Int] '[] 'Bodyless ()
  IncrementR :: Route '[Counter] '[] 'Bodyless Int
  QueryR :: Route '[Counter] '[]Bodyless Int
  TotalR :: Route '[] '[] 'Bodyless Int
data Meta captures querys request response = Meta
  { metaPath :: Path CaptureCodec captures
  , metaQuery :: Rec (Query CaptureCodec) querys
  , metaRequestBody :: RequestBody BodyCodec request
  , metaResponseBody :: ResponseBody BodyCodec response
  , metaMethod :: Text
  }
int :: CaptureCodec Int
int = showReadCaptureCodec
counter :: CaptureCodec Counter
counter = showReadCaptureCodec
bodyUnit :: BodyCodec ()
bodyUnit = BodyCodec (pure "text/plain") (const "") (const (Right ()))
bodyInt :: BodyCodec Int
bodyInt = showReadBodyCodec
meta :: Route captures querys request response -> Meta captures querys request response
meta x = case x of
  AssignR -> Meta
    (match "assign" ./ capture counter ./ match "to" ./ capture int ./ end)
    qend
    bodyless (resp bodyUnit) "post"
  IncrementR -> Meta
    (match "increment" ./ capture counter ./ end)
    qend
    bodyless (resp bodyInt) "post"
  QueryR -> Meta
    (match "query" ./ capture counter ./ end)
    qend
    bodyless (resp bodyInt) "get"
  TotalR -> Meta
    (match "total" ./ end)
    qend
    bodyless (resp bodyInt) "get"
:}

Now, we can start using our routes. To do this, we take functions that trasa exports and partially apply them to the route metadata that we have created. We can start with prepare and link:

>>> prepare = prepareWith (metaPath . meta) (metaQuery . meta) (metaRequestBody . meta)
>>> :t prepare
prepare
  :: Route captures query request response
     -> Arguments captures query request (Prepared Route response)
>>> :{
link = linkWith (mapPath captureCodecToCaptureEncoding . metaPath . meta)
                (mapQuery captureCodecToCaptureEncoding . metaQuery . meta)
:}
>>> :t link
link :: Prepared Route response -> Url

Now we can use link to encode our routes:

>>> link (prepare AssignR Green 5)
"/assign/Green/to/5"