liveBook · Manning

FromJSON

As explained in Learn Haskell by Example

FromJSON is an aeson type class whose instances define how JSON values are parsed into Haskell values.

FromJSON is aeson’s type class for parsing a JSON Value into a Haskell value. `decode` accepts a lazy ByteString and returns `Maybe a`, requiring a `FromJSON a` instance; `parseJSON` supplies the underlying `Value -> Parser a` parser. section 16.1.1

ghci> import Data.Aeson as J
ghci> :set -XOverloadedStrings
ghci> :i J.Value
type Value :: *
data Value
  = Object !Object
  | Array !Array
  | String !Text
  | Number !Scientific
  | Bool !Bool
  | Null
ghci> J.decode "{\"a\":\"Hello\", \"b\": [1,2,3]}" :: Maybe J.Value
Just (Object (fromList [("a",String "Hello"),("b",Array
 [Number 1.0,Number 2.0,Number 3.0])]))
ghci> :t J.decode
J.decode :: FromJSON a => ByteString -> Maybe a

JSON first becomes aeson’s `Value`, whose constructors represent objects, arrays, strings, numbers, booleans, and null; `decode` then selects a target type through its FromJSON instance. section 16.1.1

Write a custom parser when the JSON shape matters. `withObject` checks that a value is an object, then field operators parse required keys with `.:` and optional keys with `.:?`. A failed shape or missing required field produces a parser error rather than a value. section 16.1.1

Listing 16.1 A JSON parser for TodoEntry
{-# LANGUAGE RecordWildCards #-}

...

todoEntryParser :: J.Value -> J.Parser TodoEntry
todoEntryParser = J.withObject "TodoEntry" $
 \object -> do  #1
  entryId <- object J..:? "entryId"          #2
  text <- object J..: "text"          #3
  checked <- object J..: "checked"    #3
  rank <- object J..:? "rank"                #4
  return TodoEntry {..}   #5

This parser builds `TodoEntry` from an object: `text` and `checked` are required, while `entryId` and `rank` may be absent and become `Nothing`. section 16.1.1

Attach the parser to a type

After defining `todoEntryParser`, connect it to aeson with `instance J.FromJSON TodoEntry where parseJSON = todoEntryParser`. `J.decode` can then parse a JSON object directly as `Maybe TodoEntry`. section 16.1.1

For data types whose default JSON layout is acceptable, derive `Generic` and declare an empty FromJSON instance. aeson uses `genericParseJSON`; named record fields become object key-value pairs, `Maybe` fields are optional, and nested serializable types are handled recursively. section 16.2

Listing 16.4 A ToJSON instance for TodoEntry
{-# LANGUAGE DeriveGeneric #-}  #1

module Todos.Types where

import qualified Data.Aeson as J    #2
import qualified Data.Text as T     #2
import GHC.Generics (Generic)  #3

data TodoEntry = TodoEntry  #4
  { entryId :: Maybe Int,
    text :: T.Text,
    checked :: Bool,
    rank :: Maybe Int
  }
  deriving (Eq, Show, Generic)  #5

instance J.ToJSON TodoEntry      #6

instance J.FromJSON TodoEntry   #6

`DeriveGeneric`, `deriving Generic`, and an empty `FromJSON TodoEntry` instance replace the handwritten parser when aeson’s default representation fits the type. section 16.2

FromJSON pairs naturally with ToJSON: encoding and then decoding a value can preserve it. This roundtrip is useful for checking that generated JSON instances match the data type’s definition. section 16.2 section 16.4

How Learn Haskell by Example covers it

How deep it goes
Explains custom `Value -> Parser a` parsers, object-field helpers, errors, and Generic-derived instances without detailing Generic representations.
Examples
Uses JSON strings, a text parser, and TodoEntry objects with required `checked` and optional `entryId` and `rank` fields.
What it assumes
Introduces aeson parsing through a new project and GHCi experiments, while requiring Haskell data-type definitions to define TodoEntry.
What you can do after
Build it from scratch with a custom aeson parser or apply it via Generic-derived instances for a record type.
How it connects
Connects FromJSON with aeson Value, Parser, decode, ToJSON, Generic, and Maybe.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Haskell by Example. The section links point to the parts of the book it draws on.