-
-
Notifications
You must be signed in to change notification settings - Fork 414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
QueryParamForm Combinator #729
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,7 @@ import Network.Wai (Application, Request, Response, | |
responseLBS, vault) | ||
import Prelude () | ||
import Prelude.Compat | ||
import Web.FormUrlEncoded (FromForm, urlDecodeAsForm) | ||
import Web.HttpApiData (FromHttpApiData, parseHeaderMaybe, | ||
parseQueryParam, | ||
parseUrlPieceMaybe, | ||
|
@@ -54,7 +55,7 @@ import Servant.API ((:<|>) (..), (:>), BasicAuth, Capt | |
CaptureAll, Verb, | ||
ReflectMethod(reflectMethod), | ||
IsSecure(..), Header, QueryFlag, | ||
QueryParam, QueryParams, Raw, | ||
QueryParam, QueryParams, QueryParamForm, Raw, | ||
RemoteHost, ReqBody, Vault, | ||
WithNamedContext) | ||
import Servant.API.ContentTypes (AcceptHeader (..), | ||
|
@@ -405,6 +406,48 @@ instance (KnownSymbol sym, HasServer api context) | |
examine v | v == "true" || v == "1" || v == "" = True | ||
| otherwise = False | ||
|
||
-- | If you use @'QueryParamForm' BookSearchParams@ in one of the endpoints for your API, | ||
-- this automatically requires your server-side handler to be a function | ||
-- that takes an argument of type @['BookSearchParams']@. | ||
-- | ||
-- This lets servant worry about all key-values in the query string | ||
-- and turning each of them into a value of the type you specify. | ||
-- | ||
-- You can control how the individual values are converted from 'BookSearchParams' | ||
-- to your type by simply providing an instance of 'FromForm' for your type. | ||
-- | ||
-- Example: | ||
-- | ||
-- > data BookSearchParams = BookSearchParams | ||
-- > { title :: Text | ||
-- > { authors :: [Text] | ||
-- > , page :: Maybe Int | ||
-- > } deriving (Generic) | ||
-- > instance FromForm BookSearchParams | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably mention that we default implementation uses |
||
-- > | ||
-- > type MyApi = "books" :> QueryParamForm BookSearchParams :> Get '[JSON] [Book] | ||
-- > | ||
-- > server :: Server MyApi | ||
-- > server = getBooksBy | ||
-- > where getBooksBy :: BookSearchParams -> Handler [Book] | ||
-- > getBooksBy searchParams = ...return all books by these conditions... | ||
|
||
instance (FromForm a, HasServer api context) | ||
=> HasServer (QueryParamForm a :> api) context where | ||
|
||
type ServerT (QueryParamForm a :> api) m = | ||
a -> ServerT api m | ||
|
||
route Proxy context subserver = route (Proxy :: Proxy api) context $ | ||
subserver `addParameterCheck` withRequest paramsCheck | ||
where | ||
paramsCheck req = | ||
case urlDecodeAsForm (BL.drop 1 . BL.fromStrict $ rawQueryString req) of | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess |
||
Right form -> return form | ||
Left err -> delayedFailFatal err400 | ||
{ errBody = cs $ "Error parsing query parameter(s) to form failed: " <> err | ||
} | ||
|
||
-- | Just pass the request to the underlying application and serve its response. | ||
-- | ||
-- Example: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of type
@'BookSearchParams'@
, right?