Created
May 22, 2011 16:19
-
-
Save nbogie/985645 to your computer and use it in GitHub Desktop.
Simplest Aeson json parsing and generation example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# 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)) |
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
+1 This was helpful for me too. Thanks.