Safe Haskell | None |
---|
This module allows you to encode and decode JSON values flowing downstream through Pipes streams, possibly interleaving other stream effects.
This module builds on top of the pipes-parse
and pipes-attoparsec
packages and assumes you have read Control.Proxy.Parse.Tutorial.
- data TopLevelValue
- toTopLevelValue :: ToJSON a => a -> Maybe TopLevelValue
- encode :: (Proxy p, Monad m) => TopLevelValue -> p x' x () ByteString m ()
- encodeD :: (Proxy p, Monad m) => () -> Pipe p TopLevelValue ByteString m r
- decode :: (Monad m, Proxy p, FromJSON r) => EitherP DecodingError (StateP [ByteString] p) () (Maybe ByteString) y' y m r
- decodeD :: (Monad m, Proxy p, FromJSON b) => () -> Pipe (EitherP DecodingError (StateP [ByteString] p)) (Maybe ByteString) b m ()
- parseValue :: (Monad m, Proxy p) => EitherP ParsingError (StateP [ByteString] p) () (Maybe ByteString) y' y m TopLevelValue
- parseValueD :: (Monad m, Proxy p) => () -> Pipe (EitherP ParsingError (StateP [ByteString] p)) (Maybe ByteString) TopLevelValue m ()
- fromValue :: (Monad m, Proxy p, FromJSON r) => x -> EitherP String p x Value y' y m r
- fromValueD :: (Monad m, Proxy p, FromJSON b) => x -> EitherP String p x Value x b m r
- data DecodingError
Top level JSON values
The JSON RFC-4627 standard only allows Array
or Object
values as
top-level. The TopLevelValue
type used throughout this module in
replacement of Aesons's Value
enforces that restricion in a type-safe
manner.
If you want to ignore the standard and encode or decode any Value
, then
use the facilities exported by the Control.Proxy.Aeson.Unsafe module.
- You may use the
toTopLevelValue
function to convert anyToJSON
instance to aTopLevelValue
, if possible. Remember thatValue
is one such instance. - Use the
toJSON
method on aTopLevelValue
to obtain its underlyingValue
representation.
data TopLevelValue Source
toTopLevelValue :: ToJSON a => a -> Maybe TopLevelValueSource
Encoding
There are two different JSON encoding facilities exported by this module, and
choosing between them is easy: If you need to interleave JSON encoding
with other stream effects you must use encode
, otherwise you may use the
simpler encodeD
.
Both encoding proxies enforce the JSON RFC-4627 requirement that top-level
values are either Array
s or Object
s, as witnessed by the
TopLevelValue
type. However, if you need to ignore this requirement you may
use the similar encoding proxies exported by the Control.Proxy.Aeson.Unsafe
module.
encode :: (Proxy p, Monad m) => TopLevelValue -> p x' x () ByteString m ()Source
Encodes the given TopLevelValue
as JSON and sends it downstream, possibly
in more than one ByteString
chunk.
encodeD :: (Proxy p, Monad m) => () -> Pipe p TopLevelValue ByteString m rSource
Encodes TopLevelValue
s flowing downstream as JSON, each in possibly more
than one ByteString
chunk, and sends each chunk downstream.
Decoding
Decoding a JSON value as a Haskell type in involves two different steps:
- Parsing a raw JSON
ByteString
into aTopLevelValue
. - Converting the obtained
TopLevelValue
to the desired type, which must be aFromJSON
instance.
Any of those steps can fail, and in case of errors, the DecodingError
type explicitly states at which the step the error happened.
There are two different JSON decoding facilities exported by this module,
both perform those steps at once. Choosing between them is easy: If you
need to interleave JSON decoding with other stream effects you must use
decode
, otherwise you may use the simpler decodeD
.
These proxies use the EitherP
proxy transformer to report decoding
errors, you might use any of the facilities exported by
Control.Proxy.Trans.Either to recover from them.
If you prefer to perform each of the decoding steps separately, you
could use instead the parseValue
, parseValueD
, fromValue
or
fromValueD
proxies.
decode :: (Monad m, Proxy p, FromJSON r) => EitherP DecodingError (StateP [ByteString] p) () (Maybe ByteString) y' y m rSource
Decodes one JSON value flowing downstream.
- In case of decoding errors, a
DecodingError
exception is thrown in theEitherP
proxy transformer. - Requests more input from upstream using
draw
when needed. - Do not use this proxy if your stream has leading empty chunks or whitespace, otherwise you may get unexpected parsing errors.
Here is an example parsing loop that allows interleaving stream effects
together with decode
:
loop = do -- Skip any leading whitespace and check that we haven't reached EOF. eof <-liftP
$dropWhile
isSpace
>>isEndOfParserInput
unless
eof $ do -- 1. Possibly perform some stream effects here. -- 2. Decode one JSON element from the stream. exampleElement <-decode
-- 3. Do something with exampleElement and possibly perform -- some more stream effects. -- 4. Start all over again. loop
decodeD :: (Monad m, Proxy p, FromJSON b) => () -> Pipe (EitherP DecodingError (StateP [ByteString] p)) (Maybe ByteString) b m ()Source
Decodes consecutive JSON values flowing downstream until end of input.
- In case of decoding errors, a
DecodingError
exception is thrown in theEitherP
proxy transformer. - Requests more input from upstream using
draw
when needed. - Empty input chunks flowing downstream and whitespace in between JSON values will be discarded.
Lower level parsing
parseValue :: (Monad m, Proxy p) => EitherP ParsingError (StateP [ByteString] p) () (Maybe ByteString) y' y m TopLevelValueSource
Parses a JSON value flowing downstream into a TopLevelValue
.
- In case of parsing errors, a
ParsingError
exception is thrown in theEitherP
proxy transformer. - Requests more input from upstream using
draw
when needed. - Do not use this proxy if your stream has leading empty chunks or whitespace, otherwise you may get unexpected parsing errors.
See the documentation of decode
for an example of how to interleave
other stream effects together with this proxy.
parseValueD :: (Monad m, Proxy p) => () -> Pipe (EitherP ParsingError (StateP [ByteString] p)) (Maybe ByteString) TopLevelValue m ()Source
Parses consecutive JSON values flowing downstream as TopLevelValue
s,
until end of input.
- In case of parsing errors, a
DecodingError
exception is thrown in theEitherP
proxy transformer. - Requests more input from upstream using
draw
when needed. - Empty input chunks flowing downstream and whitespace in between JSON values will be discarded.
fromValue :: (Monad m, Proxy p, FromJSON r) => x -> EitherP String p x Value y' y m rSource
Converts any Value
flowing downstream to a FromJSON
instance.
- In case of parsing errors, a
String
exception holding the value provided by Aeson'sError
is thrown in theEitherP
proxy transformer.
See the documentation of decode
for an example of how to interleave
other stream effects together with this proxy.
Types
data DecodingError Source
An error while decoding a JSON value.
ParserError ParsingError | An Attoparsec error that happened while parsing the raw JSON string. |
ValueError String | An Aeson error that happened while trying to convert a
|