1. Bryan O'Sullivan
  2. aeson


aeson / examples / Demo.hs

{-# LANGUAGE OverloadedStrings #-}

-- Simplest example of parsing and encoding JSON with Aeson.

-- Above, we enable OverloadedStrings to allow a literal string (e.g. "name")
-- to be automatically converted to Data.Text.
-- This is useful when using Aeson's functions such as (.:) which expect Text.
-- Without it we'd need to use pack.

import Data.Aeson
import qualified Data.Aeson.Types as T

import Data.Attoparsec (parse, Result(..))
import Data.Text (Text)
import Control.Applicative ((<$>))
import Control.Monad (mzero)
import qualified Data.ByteString.Char8 as BS
-- Aeson's "encode" to JSON generates lazy bytestrings
import qualified Data.ByteString.Lazy.Char8 as BSL

-- In main we'll parse a JSON message into a Msg and display that,
-- then we'll encode a different Msg as JSON, and display it.
main ::IO ()
main = do
  print $ parseMsgFromString exampleJSONMessage
  let reply = Msg "hello Aeson!"
  putStrLn $ "Encoded reply: " ++ BSL.unpack (encode reply)

-- this is the type we'll be converting to and from JSON
data Msg = Msg Text deriving (Show)

-- here's how we should parse JSON and construct a Msg
instance FromJSON Msg where
  parseJSON (Object v) = Msg <$> v .: "message"
  parseJSON _ = mzero

-- here's how we should encode a Msg as JSON
instance ToJSON Msg where
  toJSON (Msg s) = object [ "message" .= s]

-- Here's one way to actually run the parsers.
-- Note that we do two parses:
-- once into JSON then one more into our final type.
-- There are a number of choices when dealing with parse failures.
-- Here we've chosen to parse to Maybe Msg, and a Nothing will be returned
-- if parseJSON fails.  (More informative options are available.)
-- This should take us (depending on success or failure)
-- from {"message": "hello world"} to Just (Msg "hello world")
--                              or to Nothing
-- Note also that we have not checked here that the input has been completely
-- consumed, so:
-- {"message": "hello world"} foo BIG mistake
-- would yield the same successfully translated message!
-- We could look in "rest" for the remainder.
parseMsgFromString :: String -> Maybe Msg
parseMsgFromString s =
  let bs = BS.pack s
  in case parse json bs of
       (Done rest r) -> T.parseMaybe parseJSON r :: Maybe Msg
       _             -> Nothing

-- Here's the example JSON message we're going to try to parse:
-- {"message": "hello world"}
-- It's a JSON object with a single pair, having key 'message', and a string value.
-- It could have more fields and structure, but that's all we're going to parse out of it.
exampleJSONMessage :: String
exampleJSONMessage = "{\"message\":\"hello world\"}"