Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Simplest Aeson json parsing and generation example
{-# LANGUAGE OverloadedStrings #-}
-- This is a very simple example of parsing and generating json with Aeson,
-- by a haskell newbie and intended for newbies.
--
-- This almost certainly contains a number of bad practices. It works for
-- me and hopefully will get you started.
--
-- I couldn't find a stand-alone example of Aeson usage and found it tricky to
-- get going. For example, if you don't realize to enable the language extension
-- "OverloadedStrings", then copy-pasting examples from the docs won't work and
-- you'll get something like the following:
-- Couldn't match expected type `Text' against inferred type `[Char]'
-- In the first argument of `(.=)', namely `"x"'
--
-- Figuring out the correct imports, wrangling with three or four different
-- string types, realizing that "parse" comes from attoparsec, not aeson,
-- pulling together the basic invocation... it all adds up. I still suspect
-- I'm doing it the hard way.
--
-- So, the first note:
-- The above OverloadedStrings extension allows a literal String,
-- e.g. "name", to be automatically converted to Data.Text.
-- This is useful when using Aeson's methods such as (.:) which expect Text.
module Main where
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
-- this is the type we'll construct from the contents of the 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
instance ToJSON Msg where
toJSON (Msg s) = object [ "message" .= s]
-- here's one way to actually run the parsers, to go from a string
-- to our result type (in this case Msg).
--
-- 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.
-- I've chosen to parse to Maybe Msg, so that a Nothing will be returned
-- if parseJSON fails. (More informative options are available.)
--
-- This should take us (depending on success/failure)
-- from {"message": "hello world"} to Just (Msg "hello world")
-- or to Nothing
--
-- Note also that I have not checked here that the input has been completed
-- 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\"}"
-- in main we'll parse a json message into a Msg and display that,
-- then we'll take another Msg, encode it as json, and display that.
main ::IO ()
main = do
print $ parseMsgFromString exampleJSONMessage
let reply = Msg "hello Aeson!"
putStrLn $ "Encoded reply: " ++ (BSL.unpack (encode reply))
@mgadzhi
Copy link

mgadzhi commented Apr 24, 2012

Thank you. This tutorial was very helpful for me.

@kqr
Copy link

kqr commented Mar 12, 2013

+1 This was helpful for me too. Thanks.

@joshrotenberg
Copy link

joshrotenberg commented May 29, 2013

There are a few simple Aeson examples here: https://github.com/bos/aeson/tree/master/examples and in the docs on Hackage: http://hackage.haskell.org/packages/archive/aeson/0.6.1.0/doc/html/Data-Aeson.html

(Haskell newbie myself, hope those help!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment