Safe Haskell | None |
---|---|
Language | Haskell2010 |
Several newtypes and combinators for dealing with less-than-cleanly JSON input.
Synopsis
- newtype JSONString a = JSONString {
- jsonString :: a
- (.:$) :: FromJSON a => Object -> Text -> Parser a
- (.=$) :: ToJSON a => Text -> a -> Pair
- newtype OneOrZero = OneOrZero {}
- newtype YesOrNo = YesOrNo {}
- newtype OnOrOff = OnOrOff {}
- newtype AnyBool = AnyBool {}
- newtype EmptyAsNothing a = EmptyAsNothing {
- emptyAsNothing :: Maybe a
- newtype EmptyObject = EmptyObject {
- emptyObject :: ()
- newtype RFC2822Time = RFC2822Time {}
- (.:~) :: FromJSON a => Object -> Text -> Parser a
Double-Encodings
newtype JSONString a Source #
A double-encoded JSON value.
>>>
encode (JSONString True)
"\"true\""
>>>
decode "\"true\"" :: Maybe (JSONString Bool)
Just (JSONString {jsonString = True})
JSONString | |
|
Instances
(.=$) :: ToJSON a => Text -> a -> Pair Source #
Works like aeson's (.=
), but double-encodes the value being serialized.
Booleans
There's a surprising number of ways people like to encode Booleans. At present, the
docs below lie a bit in that values which don't parse to a True
value are considered false.
For instance,
>>>
oneOrZero <$> decode "0"
Just False
>>>
oneOrZero <$> decode "1"
Just True
>>>
oneOrZero <$> decode "2"
Just False
Value
s rendered 0 or 1
>>>
oneOrZero <$> decode "1"
Just True
>>>
oneOrZero <$> decode "0"
Just False
Instances
Value
s rendered "yes" or "no"
>>>
yesOrNo <$> decode "\"yes\""
Just True
>>>
yesOrNo <$> decode "\"no\""
Just False
Instances
Value
s rendered "on" or "off"
>>>
onOrOff <$> decode "\"on\""
Just True
>>>
onOrOff <$> decode "\"off\""
Just False
Instances
Value
s rendered as more-or-less anything.
>>>
let Just bs = decode "[1, \"1\", \"true\", \"yes\", \"on\", true]"
>>>
and $ map anyBool bs
True
Instances
Maybe
newtype EmptyAsNothing a Source #
Sometimes an empty string in a JSON object actually means Nothing
>>>
emptyAsNothing <$> decode "\"\"" :: Maybe (Maybe Text)
Just Nothing
>>>
emptyAsNothing <$> decode "\"something\"" :: Maybe (Maybe Text)
Just (Just "something")
Instances
EmptyObject
newtype EmptyObject Source #
Sometimes an empty object is all there is (e.g. returned instead of HTTP 204).
>>>
decode "{}" :: Maybe EmptyObject
Just (EmptyObject {emptyObject = ()})
> eitherDecode "{\"\":\"\"}" :: Either String EmptyObject
Left "Error in $: parsing EmptyObject failed, encountered non-empty Object"
>>>
encode (EmptyObject ())
"{}"
EmptyObject | |
|
Instances
Time
newtype RFC2822Time Source #
A RFC 2822 encoded time value, allowing the modern RFC 2822 format. These parsers do not currently handle the more messy whitespace and comments allowed by the RFC.
The primary use for this if JSON APIs that dump JS datetimes as strings into the JSON.
Encoding follows the modern RFC 2822 recomended format:
>>>
encode (RFC2822Time (read "2011-10-13 18:02:00 UTC"))
"\"Thu, 13 Oct 2011 18:02:00 +0000\""
Decoding though must be far more liberal:
>>>
decode "\"Thu, 13 Oct 2011 18:02:00 GMT\"" :: Maybe RFC2822Time
Just (RFC2822Time {fromRFC2822Time = 2011-10-13 18:02:00 UTC})>>>
decode "\"Fri, 21 Nov 1997 09:55:06 -0600\"" :: Maybe RFC2822Time
Just (RFC2822Time {fromRFC2822Time = 1997-11-21 15:55:06 UTC})>>>
decode "\"Tue, 1 Jul 2003 10:52:37 +0200\"" :: Maybe RFC2822Time
Just (RFC2822Time {fromRFC2822Time = 2003-07-01 08:52:37 UTC})>>>
decode "\"Thu, 13 Feb 1969 23:32:54 -0330\"" :: Maybe RFC2822Time
Just (RFC2822Time {fromRFC2822Time = 1969-02-14 03:02:54 UTC})
RFC 822 obsolete dates:
>>>
decode "\"21 Nov 97 09:55:06 GMT\"" :: Maybe RFC2822Time
Just (RFC2822Time {fromRFC2822Time = 0097-11-21 09:55:06 UTC})
Things that should parse but don't:
decode ""Thu,n 13n Febn 1969n 23:32n -0330 (Newfoundland Time)"" :: Maybe RFC2822Time
Just (RFC2822Time {fromRFC2822Time = 1969-02-14 03:02:00 UTC})
decode ""Fri, 21 Nov 1997 09(comment): 55 : 06 -0600"" :: Maybe RFC2822Time
Just (RFC2822Time {fromRFC2822Time = 1997-11-21 15:55:06 UTC})
Instances
Case Insensitive Keys
(.:~) :: FromJSON a => Object -> Text -> Parser a Source #
Some systems attempt to treat keys in JSON objects case-insensitively(ish). Golang's JSON
marshalling is a prominent example: https://golang.org/pkg/encoding/json/#Marshal. The
(.:~
) combinator works like (.:
), but if it fails to match, attempts to find a
case-insensitive variant of the key being sought. If there is an exact match, (.:~
) will
take that; if there are multiple non-exact matches, the choice of selected value is
unspecified. Mnemonic: ~
swaps case in vi.
>>>
data Foo = Foo Int deriving (Read, Show)
>>>
instance FromJSON Foo where parseJSON (Object o) = Foo <$> o .:~ "foo"
>>>
decode "{\"FOO\": 12}" :: Maybe Foo
Just (Foo 12)>>>
decode "{\"foo\": 17, \"FOO\": 12}" :: Maybe Foo
Just (Foo 17)