git.iko.soy/typeable/http-api-data
on master help sign in
Merge pull request #20 from fizruk/url-pieces

Helpers for multiple URL pieces and query parameters

commita12c5cd4e2c35b285507758fcf0a1d098da7ee0a authorNickolay Kudasov <fizruk@users.noreply.github.com> dateMon 12 Oct 2015, 18:59 (11 years ago) parentcdc4b9378a25ab
4 files changed+68−15
CHANGELOG.md+7 README.md+10−8 Web/HttpApiData.hs+17−6 Web/HttpApiData/Internal.hs+34−1
CHANGELOG.md+7
@@ -1,3 +1,10 @@
1+Unreleased changes
2+---
3+
4+* Add helpers for multiple URL pieces and query params:
5+ * `toUrlPieces`, `parseUrlPieces`
6+ * `toQueryParams`, `parseQueryParams`
7+
180.2
29---
310
README.md+10−8
@@ -11,22 +11,24 @@ Booleans:
1111
1212```
1313>>> toUrlPiece True
14−"True"
15−>>> parseUrlPiece "False" :: Either Text Bool
14+"true"
15+>>> parseUrlPiece "false" :: Either Text Bool
1616Right False
17−>>> parseUrlPiece "something else" :: Either Text Bool
18−Left "could not parse: `something else'"
17+>>> parseUrlPieces ["true", "false", "undefined"] :: Either Text [Bool]
18+Left "could not parse: `undefined'"
1919```
2020
2121Numbers:
2222
2323```
24−>>> toUrlPiece 45.2
24+>>> toQueryParam 45.2
2525"45.2"
26−>>> parseUrlPiece "452" :: Either Text Int
26+>>> parseQueryParam "452" :: Either Text Int
2727Right 452
28−>>> parseUrlPiece "256" :: Either Text Int8
29−Left "out of bounds: `256' (should be between -128 and 127)"
28+>>> toQueryParams [1..5]
29+["1","2","3","4","5"]
30+>>> parseQueryParams ["127", "255"] :: Either Text [Int8]
31+Left "out of bounds: `255' (should be between -128 and 127)"
3032```
3133
3234Strings:
Web/HttpApiData.hs+17−6
@@ -19,6 +19,14 @@ module Web.HttpApiData (
1919 parseHeaderWithPrefix,
2020 parseQueryParamWithPrefix,
2121
22+ -- * Multiple URL pieces
23+ toUrlPieces,
24+ parseUrlPieces,
25+
26+ -- * Multiple query params
27+ toQueryParams,
28+ parseQueryParams,
29+
2230 -- * Other helpers
2331 showTextData,
2432 readTextData,
@@ -45,17 +53,19 @@ import Web.HttpApiData.Internal
4553-- "true"
4654-- >>> parseUrlPiece "false" :: Either Text Bool
4755-- Right False
48−-- >>> parseUrlPiece "something else" :: Either Text Bool
49−-- Left "could not parse: `something else'"
56+-- >>> parseUrlPieces ["true", "false", "undefined"] :: Either Text [Bool]
57+-- Left "could not parse: `undefined'"
5058--
5159-- Numbers:
5260--
53−-- >>> toUrlPiece 45.2
61+-- >>> toQueryParam 45.2
5462-- "45.2"
55−-- >>> parseUrlPiece "452" :: Either Text Int
63+-- >>> parseQueryParam "452" :: Either Text Int
5664-- Right 452
57−-- >>> parseUrlPiece "256" :: Either Text Int8
58−-- Left "out of bounds: `256' (should be between -128 and 127)"
65+-- >>> toQueryParams [1..5]
66+-- ["1","2","3","4","5"]
67+-- >>> parseQueryParams ["127", "255"] :: Either Text [Int8]
68+-- Left "out of bounds: `255' (should be between -128 and 127)"
5969--
6070-- Strings:
6171--
@@ -70,3 +80,4 @@ import Web.HttpApiData.Internal
7080-- "2015-10-03"
7181-- >>> toGregorian <$> parseQueryParam "2016-12-01"
7282-- Right (2016,12,1)
83+
Web/HttpApiData/Internal.hs+34−1
@@ -11,6 +11,7 @@ module Web.HttpApiData.Internal where
1111
1212#if __GLASGOW_HASKELL__ < 710
1313import Control.Applicative
14+import Data.Traversable (Traversable(traverse))
1415#endif
1516import Control.Arrow ((&&&))
1617
@@ -71,6 +72,38 @@ class FromHttpApiData a where
7172 parseQueryParam :: Text -> Either Text a
7273 parseQueryParam = parseUrlPiece
7374
75+-- | Convert multiple values to a list of URL pieces.
76+--
77+-- >>> toUrlPieces [1, 2, 3]
78+-- ["1","2","3"]
79+toUrlPieces :: (Functor t, ToHttpApiData a) => t a -> t Text
80+toUrlPieces = fmap toUrlPiece
81+
82+-- | Parse multiple URL pieces.
83+--
84+-- >>> parseUrlPieces ["true", "false"] :: Either Text [Bool]
85+-- Right [True,False]
86+-- >>> parseUrlPieces ["123", "hello", "world"] :: Either Text [Int]
87+-- Left "could not parse: `hello' (input does not start with a digit)"
88+parseUrlPieces :: (Traversable t, FromHttpApiData a) => t Text -> Either Text (t a)
89+parseUrlPieces = traverse parseUrlPiece
90+
91+-- | Convert multiple values to a list of query parameter values.
92+--
93+-- >>> toQueryParams [fromGregorian 2015 10 03, fromGregorian 2015 12 01]
94+-- ["2015-10-03","2015-12-01"]
95+toQueryParams :: (Functor t, ToHttpApiData a) => t a -> t Text
96+toQueryParams = fmap toQueryParam
97+
98+-- | Parse multiple query parameters.
99+--
100+-- >>> parseQueryParams ["1", "2", "3"] :: Either Text [Int]
101+-- Right [1,2,3]
102+-- >>> parseQueryParams ["64", "128", "256"] :: Either Text [Word8]
103+-- Left "out of bounds: `256' (should be between 0 and 255)"
104+parseQueryParams :: (Traversable t, FromHttpApiData a) => t Text -> Either Text (t a)
105+parseQueryParams = traverse parseQueryParam
106+
74107-- | Parse URL path piece in a @'Maybe'@.
75108--
76109-- >>> parseUrlPieceMaybe "12" :: Maybe Int
@@ -271,7 +304,7 @@ readTextData = parseMaybeTextData (readMaybe . T.unpack)
271304runReader :: Reader a -> Text -> Either Text a
272305runReader reader input =
273306 case reader input of
274− Left err -> Left (T.pack err)
307+ Left err -> Left ("could not parse: `" <> input <> "' (" <> T.pack err <> ")")
275308 Right (x, rest)
276309 | T.null rest -> Right x
277310 | otherwise -> defaultParseError input