@@ -1,22 +1,6 @@
1{-# LANGUAGE PolyKinds #-}
1{-# LANGUAGE PolyKinds #-}
2−{-# LANGUAGE TypeFamilies #-}
3−{-# LANGUAGE TypeOperators #-}
4−{-# LANGUAGE FlexibleContexts #-}
5−{-# LANGUAGE FlexibleInstances #-}
6−{-# LANGUAGE OverloadedStrings #-}
7−{-# LANGUAGE ScopedTypeVariables #-}
8module Servant.API.QueryParam where
2module Servant.API.QueryParam where
12−import Data.String.Conversions
14−import Network.HTTP.Types
16−import Servant.API.Sub
17−import Servant.Common.Text
20-- | Lookup the value associated to the @sym@ query string parameter
4-- | Lookup the value associated to the @sym@ query string parameter
21-- and try to extract it as a value of type @a@.
5-- and try to extract it as a value of type @a@.
@@ -26,46 +10,6 @@ import Servant.Server
26-- > type MyApi = "books" :> QueryParam "author" Text :> Get [Book]
10-- > type MyApi = "books" :> QueryParam "author" Text :> Get [Book]
27data QueryParam sym a
11data QueryParam sym a
29−-- | If you use @'QueryParam' "author" Text@ in one of the endpoints for your API,
30−-- this automatically requires your server-side handler to be a function
31−-- that takes an argument of type @'Maybe' 'Text'@.
33−-- This lets servant worry about looking it up in the query string
34−-- and turning it into a value of the type you specify, enclosed
35−-- in 'Maybe', because it may not be there and servant would then
36−-- hand you 'Nothing'.
38−-- You can control how it'll be converted from 'Text' to your type
39−-- by simply providing an instance of 'FromText' for your type.
43−-- > type MyApi = "books" :> QueryParam "author" Text :> Get [Book]
45−-- > server :: Server MyApi
46−-- > server = getBooksBy
47−-- > where getBooksBy :: Maybe Text -> EitherT (Int, String) IO [Book]
48−-- > getBooksBy Nothing = ...return all books...
49−-- > getBooksBy (Just author) = ...return books by the given author...
50−instance (KnownSymbol sym, FromText a, HasServer sublayout)
51− => HasServer (QueryParam sym a :> sublayout) where
53− type Server (QueryParam sym a :> sublayout) =
54− Maybe a -> Server sublayout
56− route Proxy subserver request respond = do
57− let querytext = parseQueryText $ rawQueryString request
59− case lookup paramname querytext of
60− Nothing -> Nothing -- param absent from the query string
61− Just Nothing -> Nothing -- param present with no value -> Nothing
62− Just (Just v) -> fromText v -- if present, we try to convert to
65− route (Proxy :: Proxy sublayout) (subserver param) request respond
67− where paramname = cs $ symbolVal (Proxy :: Proxy sym)
69-- | Lookup the values associated to the @sym@ query string parameter
13-- | Lookup the values associated to the @sym@ query string parameter
70-- and try to extract it as a value of type @[a]@. This is typically
14-- and try to extract it as a value of type @[a]@. This is typically
71-- meant to support query string parameters of the form
15-- meant to support query string parameters of the form
@@ -79,46 +23,6 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
79-- > type MyApi = "books" :> QueryParams "authors" Text :> Get [Book]
23-- > type MyApi = "books" :> QueryParams "authors" Text :> Get [Book]
80data QueryParams sym a
24data QueryParams sym a
82−-- | If you use @'QueryParams' "authors" Text@ in one of the endpoints for your API,
83−-- this automatically requires your server-side handler to be a function
84−-- that takes an argument of type @['Text']@.
86−-- This lets servant worry about looking up 0 or more values in the query string
87−-- associated to @authors@ and turning each of them into a value of
88−-- the type you specify.
90−-- You can control how the individual values are converted from 'Text' to your type
91−-- by simply providing an instance of 'FromText' for your type.
95−-- > type MyApi = "books" :> QueryParams "authors" Text :> Get [Book]
97−-- > server :: Server MyApi
98−-- > server = getBooksBy
99−-- > where getBooksBy :: [Text] -> EitherT (Int, String) IO [Book]
100−-- > getBooksBy authors = ...return all books by these authors...
101−instance (KnownSymbol sym, FromText a, HasServer sublayout)
102− => HasServer (QueryParams sym a :> sublayout) where
104− type Server (QueryParams sym a :> sublayout) =
105− [a] -> Server sublayout
107− route Proxy subserver request respond = do
108− let querytext = parseQueryText $ rawQueryString request
109− -- if sym is "foo", we look for query string parameters
110− -- named "foo" or "foo[]" and call fromText on the
111− -- corresponding values
112− parameters = filter looksLikeParam querytext
113− values = catMaybes $ map (convert . snd) parameters
115− route (Proxy :: Proxy sublayout) (subserver values) request respond
117− where paramname = cs $ symbolVal (Proxy :: Proxy sym)
118− looksLikeParam (name, _) = name == paramname || name == (paramname <> "[]")
119− convert Nothing = Nothing
120− convert (Just v) = fromText v
122-- | Lookup a potentially value-less query string parameter
26-- | Lookup a potentially value-less query string parameter
123-- with boolean semantics. If the param @sym@ is there without any value,
27-- with boolean semantics. If the param @sym@ is there without any value,
124-- or if it's there with value "true" or "1", it's interpreted as 'True'.
28-- or if it's there with value "true" or "1", it's interpreted as 'True'.
@@ -129,34 +33,3 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
129-- > -- /books?published
33-- > -- /books?published
130-- > type MyApi = "books" :> QueryFlag "published" :> Get [Book]
34-- > type MyApi = "books" :> QueryFlag "published" :> Get [Book]
131data QueryFlag sym
35data QueryFlag sym
133−-- | If you use @'QueryFlag' "published"@ in one of the endpoints for your API,
134−-- this automatically requires your server-side handler to be a function
135−-- that takes an argument of type 'Bool'.
139−-- > type MyApi = "books" :> QueryFlag "published" :> Get [Book]
141−-- > server :: Server MyApi
142−-- > server = getBooks
143−-- > where getBooks :: Bool -> EitherT (Int, String) IO [Book]
144−-- > getBooks onlyPublished = ...return all books, or only the ones that are already published, depending on the argument...
145−instance (KnownSymbol sym, HasServer sublayout)
146− => HasServer (QueryFlag sym :> sublayout) where
148− type Server (QueryFlag sym :> sublayout) =
149− Bool -> Server sublayout
151− route Proxy subserver request respond = do
152− let querytext = parseQueryText $ rawQueryString request
153− param = case lookup paramname querytext of
154− Just Nothing -> True -- param is there, with no value
155− Just (Just v) -> examine v -- param with a value
156− Nothing -> False -- param not in the query string
158− route (Proxy :: Proxy sublayout) (subserver param) request respond
160− where paramname = cs $ symbolVal (Proxy :: Proxy sym)
161− examine v | v == "true" || v == "1" || v == "" = True