{-# OPTIONS_GHC -fno-warn-unused-imports #-} {-| 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. -} module Trasa.Tutorial ( -- * Dispatch and Routing -- $dispatchandrouting ) where import Trasa.Core import Data.Vinyl (Rec) import Data.Kind (Type) import Data.Text (Text) -- $setup -- >>> :set -XDataKinds -- >>> :set -XKindSignatures -- >>> :set -XGADTs -- >>> :set -XOverloadedStrings -- $dispatchandrouting -- 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" -- --