@@ -5,6 +5,27 @@
5{-# LANGUAGE ScopedTypeVariables #-}
5{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE TemplateHaskell #-}
6{-# LANGUAGE TemplateHaskell #-}
7{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
7{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
8+-- | QuasiQuoting utilities for API types.
10+-- 'sitemap' allows you to write your type in a very natural way:
14+-- PUT hello String -> ()
15+-- POST hello/p:Int String -> ()
16+-- GET hello/?name:String Int
23+-- "hello" :> ReqBody String :> Put ()
24+-- :<|> "hello" :> Capture "p" Int :> ReqBody String :> Post ()
25+-- :<|> "hello" :> QueryParam "name" String :> Get Int
28+-- Note the '/' before a 'QueryParam'!
8module Servant.Utils.ApiQuasiQuoting where
29module Servant.Utils.ApiQuasiQuoting where
10import Control.Monad (void)
31import Control.Monad (void)
@@ -23,6 +44,11 @@ import Servant.API.ReqBody
23import Servant.API.Sub
44import Servant.API.Sub
24import Servant.API.Alternative
45import Servant.API.Alternative
47+-- | Finally-tagless encoding for our DSL.
48+-- Keeping 'repr'' and 'repr' distinct when writing functions with an
49+-- @ExpSYM@ context ensures certain invariants (for instance, that there is
50+-- only one of 'get', 'post', 'put', and 'delete' in a value), but
51+-- sometimes requires a little more work.
26class ExpSYM repr' repr | repr -> repr', repr' -> repr where
52class ExpSYM repr' repr | repr -> repr', repr' -> repr where
27 lit :: String -> repr' -> repr
53 lit :: String -> repr' -> repr
28 capture :: String -> String -> repr -> repr
54 capture :: String -> String -> repr -> repr
@@ -148,6 +174,23 @@ parseAll = do
148 where union :: Type -> Type -> Type
174 where union :: Type -> Type -> Type
149 union a = AppT (AppT (ConT ''(:<|>)) a)
175 union a = AppT (AppT (ConT ''(:<|>)) a)
177+-- | The sitemap QuasiQuoter.
179+-- * @.../<var>:<type>/...@ becomes a capture
181+-- * @.../?<var>:<type>@ becomes a query parameter
183+-- * @<method> ... <typ>@ becomes a method returning @<typ>@
185+-- * @<method> ... <typ1> -> <typ2>@ becomes a method with request
186+-- body of @<typ1>@ and returning @<typ2>@
188+-- Comments are allowed, and have the standard Haskell format
192+-- * @{- ... -}@ for block
151sitemap :: QuasiQuoter
194sitemap :: QuasiQuoter
152sitemap = QuasiQuoter { quoteExp = undefined
195sitemap = QuasiQuoter { quoteExp = undefined
153 , quotePat = undefined
196 , quotePat = undefined