@@ -21,6 +21,8 @@ module Web.HttpApiData (
21 readEitherUrlPiece,
21 readEitherUrlPiece,
24+import Control.Applicative
24import Data.Monoid
26import Data.Monoid
25import Data.ByteString (ByteString)
27import Data.ByteString (ByteString)
@@ -73,11 +75,15 @@ class FromHttpApiData a where
73 parseQueryParam :: Text -> Either Text a
75 parseQueryParam :: Text -> Either Text a
74 parseQueryParam = parseUrlPiece
76 parseQueryParam = parseUrlPiece
78+-- | Default parsing error.
79+defaultParseError :: Text -> Either Text a
80+defaultParseError input = Left ("could not convert: `" <> input <> "'")
76-- | Convert @'Maybe'@ parser into @'Either' 'Text'@ parser with default error message.
82-- | Convert @'Maybe'@ parser into @'Either' 'Text'@ parser with default error message.
77parseMaybeHttpApiData :: (Text -> Maybe a) -> (Text -> Either Text a)
83parseMaybeHttpApiData :: (Text -> Maybe a) -> (Text -> Either Text a)
78parseMaybeHttpApiData parse input =
84parseMaybeHttpApiData parse input =
79 case parse input of
85 case parse input of
80− Nothing -> Left ("could not convert: `" <> input <> "'")
86+ Nothing -> defaultParseError input
81 Just val -> Right val
87 Just val -> Right val
83-- | Convert to URL piece using @'Show'@ instance.
89-- | Convert to URL piece using @'Show'@ instance.
@@ -99,7 +105,7 @@ runReader reader input =
99 Left err -> Left (T.pack err)
105 Left err -> Left (T.pack err)
100 Right (x, rest)
106 Right (x, rest)
101 | T.null rest -> Right x
107 | T.null rest -> Right x
102− | otherwise -> Left ("could not convert: `" <> input <> "'")
108+ | otherwise -> defaultParseError input
104-- | Run @'Reader'@ to parse bounded integral value with bounds checking.
110-- | Run @'Reader'@ to parse bounded integral value with bounds checking.
105parseBounded :: forall a. (Bounded a, Integral a) => Reader Integer -> Text -> Either Text a
111parseBounded :: forall a. (Bounded a, Integral a) => Reader Integer -> Text -> Either Text a
@@ -112,6 +118,12 @@ parseBounded reader input = do
112 l = toInteger (minBound :: a)
118 l = toInteger (minBound :: a)
113 h = toInteger (maxBound :: a)
119 h = toInteger (maxBound :: a)
124+instance ToHttpApiData () where
115instance ToHttpApiData Bool where toUrlPiece = showUrlPiece
127instance ToHttpApiData Bool where toUrlPiece = showUrlPiece
116instance ToHttpApiData Double where toUrlPiece = showUrlPiece
128instance ToHttpApiData Double where toUrlPiece = showUrlPiece
117instance ToHttpApiData Float where toUrlPiece = showUrlPiece
129instance ToHttpApiData Float where toUrlPiece = showUrlPiece
@@ -131,6 +143,20 @@ instance ToHttpApiData Text where toUrlPiece = id
131instance ToHttpApiData L.Text where toUrlPiece = L.toStrict
143instance ToHttpApiData L.Text where toUrlPiece = L.toStrict
132instance ToHttpApiData Day where toUrlPiece = showUrlPiece
144instance ToHttpApiData Day where toUrlPiece = showUrlPiece
147+-- >>> toUrlPiece (Just "Hello")
149+instance ToHttpApiData a => ToHttpApiData (Maybe a) where
150+ toUrlPiece (Just x) = "Just " <> toUrlPiece x
151+ toUrlPiece Nothing = "Nothing"
154+-- >>> parseUrlPiece "_" :: Either Text ()
156+instance FromHttpApiData () where
157+ parseUrlPiece "_" = return ()
158+ parseUrlPiece s = defaultParseError s
134instance FromHttpApiData Bool where parseUrlPiece = readEitherUrlPiece
160instance FromHttpApiData Bool where parseUrlPiece = readEitherUrlPiece
135instance FromHttpApiData Double where parseUrlPiece = runReader rational
161instance FromHttpApiData Double where parseUrlPiece = runReader rational
136instance FromHttpApiData Float where parseUrlPiece = runReader rational
162instance FromHttpApiData Float where parseUrlPiece = runReader rational
@@ -150,6 +176,16 @@ instance FromHttpApiData Text where parseUrlPiece = Right
150instance FromHttpApiData L.Text where parseUrlPiece = Right . L.fromStrict
176instance FromHttpApiData L.Text where parseUrlPiece = Right . L.fromStrict
151instance FromHttpApiData Day where parseUrlPiece = readEitherUrlPiece
177instance FromHttpApiData Day where parseUrlPiece = readEitherUrlPiece
180+-- >>> parseUrlPiece "Just 123" :: Either Text (Maybe Int)
182+instance FromHttpApiData a => FromHttpApiData (Maybe a) where
183+ parseUrlPiece "Nothing" = return Nothing
185+ case T.stripPrefix "Just " s of
186+ Nothing -> defaultParseError s
187+ Just x -> Just <$> parseUrlPiece x
153-- $examples
189-- $examples
155-- Booleans:
191-- Booleans: