forked from haskell-servant/servant
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Servant.API.Modifiers to servant
Changes Header, ReqBody and QueryParam to take a modifier list. First step to implement haskell-servant#856 Only adjust Links implementation. ResponseHeader story turns to be somewhat ugly, but it can be made elegant when haskell-servant#841 is implemnted, then we can omit HList aka Header Heterogenous List implementation.
- Loading branch information
Showing
9 changed files
with
187 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
{-# LANGUAGE DataKinds #-} | ||
{-# LANGUAGE KindSignatures #-} | ||
{-# LANGUAGE FlexibleContexts #-} | ||
{-# LANGUAGE ScopedTypeVariables #-} | ||
{-# LANGUAGE TypeFamilies #-} | ||
{-# LANGUAGE TypeOperators #-} | ||
module Servant.API.Modifiers ( | ||
-- * Required / optional argument | ||
Required, Optional, | ||
FoldRequired, FoldRequired', | ||
-- * Lenient / strict parsing | ||
Lenient, Strict, | ||
FoldLenient, FoldLenient', | ||
-- * Utilities | ||
RequestArgument, | ||
unfoldRequestArgument, | ||
) where | ||
|
||
import Data.Proxy (Proxy (..)) | ||
import Data.Singletons.Bool (SBool (..), SBoolI (..)) | ||
import Data.Text (Text) | ||
import Data.Type.Bool (If) | ||
|
||
-- | Required argument. Not wrapped. | ||
data Required | ||
|
||
-- | Optional argument. Wrapped in 'Maybe'. | ||
data Optional | ||
|
||
-- | Fold modifier list to decide whether argument is required. | ||
-- | ||
-- >>> :kind! FoldRequired '[Required, Description "something"] | ||
-- FoldRequired '[Required, Description "something"] :: Bool | ||
-- = 'True | ||
-- | ||
-- >>> :kind! FoldRequired '[Required, Optional] | ||
-- FoldRequired '[Required, Optional] :: Bool | ||
-- = 'False | ||
-- | ||
-- >>> :kind! FoldRequired '[] | ||
-- FoldRequired '[] :: Bool | ||
-- = 'False | ||
-- | ||
type FoldRequired mods = FoldRequired' 'False mods | ||
|
||
-- | Implementation of 'FoldRequired'. | ||
type family FoldRequired' (acc :: Bool) (mods :: [*]) :: Bool where | ||
FoldRequired' acc '[] = acc | ||
FoldRequired' acc (Required ': mods) = FoldRequired' 'True mods | ||
FoldRequired' acc (Optional ': mods) = FoldRequired' 'False mods | ||
FoldRequired' acc (mod ': mods) = FoldRequired' acc mods | ||
|
||
-- | Leniently parsed argument, i.e. parsing never fail. Wrapped in @'Either' 'Text'@. | ||
data Lenient | ||
|
||
-- | Strictly parsed argument. Not wrapped. | ||
data Strict | ||
|
||
-- | Fold modifier list to decide whether argument should be parsed strictly or leniently. | ||
-- | ||
-- >>> :kind! FoldLenient '[] | ||
-- FoldLenient '[] :: Bool | ||
-- = 'False | ||
-- | ||
type FoldLenient mods = FoldLenient' 'False mods | ||
|
||
-- | Implementation of 'FoldLenient'. | ||
type family FoldLenient' (acc :: Bool) (mods :: [*]) :: Bool where | ||
FoldLenient' acc '[] = acc | ||
FoldLenient' acc (Lenient ': mods) = FoldLenient' 'True mods | ||
FoldLenient' acc (Strict ': mods) = FoldLenient' 'False mods | ||
FoldLenient' acc (mod ': mods) = FoldLenient' acc mods | ||
|
||
-- | Helper type alias. | ||
-- | ||
-- By default argument is 'Optional' and 'Strict'. | ||
-- | ||
-- * 'Required', 'Strict' ↦ @a@ | ||
-- | ||
-- * 'Required', 'Lenient' ↦ @'Either' 'Text' a@ | ||
-- | ||
-- * 'Optional', 'Strict' ↦ @'Maybe' a@ | ||
-- | ||
-- * 'Optional', 'Lenient' ↦ @'Maybe' ('Either' 'Text' a)@ | ||
-- | ||
type RequestArgument mods a = | ||
If (FoldRequired mods) | ||
(If (FoldLenient mods) (Either Text a) a) | ||
(Maybe (If (FoldLenient mods) (Either Text a) a)) | ||
|
||
-- | Unfold value into 'RequestArgument'. | ||
unfoldRequestArgument | ||
:: forall mods m a. (Monad m, SBoolI (FoldRequired mods), SBoolI (FoldLenient mods)) | ||
=> Proxy mods | ||
-> m (RequestArgument mods a) -- ^ error when argument is required | ||
-> (Text -> m (RequestArgument mods a)) -- ^ error when argument is strictly parsed | ||
-> Maybe (Either Text a) -- ^ value | ||
-> m (RequestArgument mods a) | ||
unfoldRequestArgument _ errReq errSt mex = | ||
case (sbool :: SBool (FoldRequired mods), mex, sbool :: SBool (FoldLenient mods)) of | ||
(STrue, Nothing, _) -> errReq | ||
(SFalse, Nothing, _) -> return Nothing | ||
(STrue, Just ex, STrue) -> return ex | ||
(STrue, Just ex, SFalse) -> either errSt return ex | ||
(SFalse, Just ex, STrue) -> return (Just ex) | ||
(SFalse, Just ex, SFalse) -> either errSt (return . Just) ex | ||
|
||
-- $setup | ||
-- >>> import Servant.API |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.