@@ -5,7 +5,28 @@
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@!
8−module Servant.Utils.ApiQuasiQuoting where
29+module Servant.QQ where
10import Control.Monad (void)
31import Control.Monad (void)
11import Control.Applicative hiding (many, (<|>), optional)
32import Control.Applicative hiding (many, (<|>), optional)
@@ -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,19 @@ 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
180+-- * @.../?<var>:<type>@ becomes a query parameter
181+-- * @<method> ... <typ>@ becomes a method returning @<typ>@
182+-- * @<method> ... <typ1> -> <typ2>@ becomes a method with request
183+-- body of @<typ1>@ and returning @<typ2>@
185+-- Comments are allowed, and have the standard Haskell format
188+-- * @{- ... -}@ for block
151sitemap :: QuasiQuoter
190sitemap :: QuasiQuoter
152sitemap = QuasiQuoter { quoteExp = undefined
191sitemap = QuasiQuoter { quoteExp = undefined
153 , quotePat = undefined
192 , quotePat = undefined