git.iko.soy/typeable/http-api-data
on master help sign in
Merge pull request #20 from fizruk/url-pieces
a12c5cdNickolay Kudasov
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+
10.2
80.2
2---
9---
3
10
README.md+10−8
@@ -11,22 +11,24 @@ Booleans:
11
11
12```
12```
13>>> toUrlPiece True
13>>> toUrlPiece True
14−"True"
14+"true"
15−>>> parseUrlPiece "False" :: Either Text Bool
15+>>> parseUrlPiece "false" :: Either Text Bool
16Right False
16Right False
17−>>> parseUrlPiece "something else" :: Either Text Bool
17+>>> parseUrlPieces ["true", "false", "undefined"] :: Either Text [Bool]
18−Left "could not parse: `something else'"
18+Left "could not parse: `undefined'"
19```
19```
20
20
21Numbers:
21Numbers:
22
22
23```
23```
24−>>> toUrlPiece 45.2
24+>>> toQueryParam 45.2
25"45.2"
25"45.2"
26−>>> parseUrlPiece "452" :: Either Text Int
26+>>> parseQueryParam "452" :: Either Text Int
27Right 452
27Right 452
28+>>> toQueryParams [1..5]
29+["1","2","3","4","5"]
28−>>> parseUrlPiece "256" :: Either Text Int8
30+>>> parseQueryParams ["127", "255"] :: Either Text [Int8]
29−Left "out of bounds: `256' (should be between -128 and 127)"
31+Left "out of bounds: `255' (should be between -128 and 127)"
30```
32```
31
33
32Strings:
34Strings:
Web/HttpApiData.hs+17−6
@@ -19,6 +19,14 @@ module Web.HttpApiData (
19 parseHeaderWithPrefix,
19 parseHeaderWithPrefix,
20 parseQueryParamWithPrefix,
20 parseQueryParamWithPrefix,
21
21
22+ -- * Multiple URL pieces
23+ toUrlPieces,
24+ parseUrlPieces,
25+
26+ -- * Multiple query params
27+ toQueryParams,
28+ parseQueryParams,
29+
22 -- * Other helpers
30 -- * Other helpers
23 showTextData,
31 showTextData,
24 readTextData,
32 readTextData,
@@ -45,17 +53,19 @@ import Web.HttpApiData.Internal
45-- "true"
53-- "true"
46-- >>> parseUrlPiece "false" :: Either Text Bool
54-- >>> parseUrlPiece "false" :: Either Text Bool
47-- Right False
55-- Right False
48−-- >>> parseUrlPiece "something else" :: Either Text Bool
56+-- >>> parseUrlPieces ["true", "false", "undefined"] :: Either Text [Bool]
49−-- Left "could not parse: `something else'"
57+-- Left "could not parse: `undefined'"
50--
58--
51-- Numbers:
59-- Numbers:
52--
60--
53−-- >>> toUrlPiece 45.2
61+-- >>> toQueryParam 45.2
54-- "45.2"
62-- "45.2"
55−-- >>> parseUrlPiece "452" :: Either Text Int
63+-- >>> parseQueryParam "452" :: Either Text Int
56-- Right 452
64-- Right 452
65+-- >>> toQueryParams [1..5]
66+-- ["1","2","3","4","5"]
57−-- >>> parseUrlPiece "256" :: Either Text Int8
67+-- >>> parseQueryParams ["127", "255"] :: Either Text [Int8]
58−-- Left "out of bounds: `256' (should be between -128 and 127)"
68+-- Left "out of bounds: `255' (should be between -128 and 127)"
59--
69--
60-- Strings:
70-- Strings:
61--
71--
@@ -70,3 +80,4 @@ import Web.HttpApiData.Internal
70-- "2015-10-03"
80-- "2015-10-03"
71-- >>> toGregorian <$> parseQueryParam "2016-12-01"
81-- >>> toGregorian <$> parseQueryParam "2016-12-01"
72-- Right (2016,12,1)
82-- Right (2016,12,1)
83+
Web/HttpApiData/Internal.hs+34−1
@@ -11,6 +11,7 @@ module Web.HttpApiData.Internal where
11
11
12#if __GLASGOW_HASKELL__ < 710
12#if __GLASGOW_HASKELL__ < 710
13import Control.Applicative
13import Control.Applicative
14+import Data.Traversable (Traversable(traverse))
14#endif
15#endif
15import Control.Arrow ((&&&))
16import Control.Arrow ((&&&))
16
17
@@ -71,6 +72,38 @@ class FromHttpApiData a where
71 parseQueryParam :: Text -> Either Text a
72 parseQueryParam :: Text -> Either Text a
72 parseQueryParam = parseUrlPiece
73 parseQueryParam = parseUrlPiece
73
74
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+
74-- | Parse URL path piece in a @'Maybe'@.
107-- | Parse URL path piece in a @'Maybe'@.
75--
108--
76-- >>> parseUrlPieceMaybe "12" :: Maybe Int
109-- >>> parseUrlPieceMaybe "12" :: Maybe Int
@@ -271,7 +304,7 @@ readTextData = parseMaybeTextData (readMaybe . T.unpack)
271runReader :: Reader a -> Text -> Either Text a
304runReader :: Reader a -> Text -> Either Text a
272runReader reader input =
305runReader reader input =
273 case reader input of
306 case reader input of
274− Left err -> Left (T.pack err)
307+ Left err -> Left ("could not parse: `" <> input <> "' (" <> T.pack err <> ")")
275 Right (x, rest)
308 Right (x, rest)
276 | T.null rest -> Right x
309 | T.null rest -> Right x
277 | otherwise -> defaultParseError input
310 | otherwise -> defaultParseError input