yamlet-aeson

Use the FromJSON and ToJSON instances of aeson with yamlet.

Stackage Nightly 2026-11-03:1.0.0.1
Latest on Hackage:1.0.0.1

See all snapshots yamlet-aeson appears in

BSD-3-Clause licensed by Andrzej Rybczak
Maintained by [email protected]
This version can be pinned in stack with:yamlet-aeson-1.0.0.1@sha256:1af9a0cc79d669c422181e238c0bd5034e6623abda94f484bf159e5ea082be24,4138

Module documentation for 1.0.0.1

yamlet-aeson

CI Hackage Stackage LTS Stackage Nightly

Use the FromJSON and ToJSON instances of aeson with yamlet, for the types that have no FromYaml and ToYaml instances yet, e.g. in a program that moves from the yaml package to yamlet.

  • A value in ViaAeson decodes and encodes with its FromJSON and ToJSON instances, so the functions of yamlet work with it, e.g. decodeFile @(ViaAeson Config). A program can try yamlet by changing only the places that decode and encode.
  • A type with FromJSON and ToJSON instances can derive its FromYaml and ToYaml instances via ViaAeson, e.g. in a program that reads and writes both JSON and YAML and keeps one set of instances.
  • An error of a decoder of aeson points to the node that caused it, with the line, the column and the path. An error of a key of a map points to the value of the key, and its path names the key.
  • The encoder keeps the order of the fields of a type whose instance defines toEncoding, e.g. with genericToEncoding.
  • The package also has the FromYaml and ToYaml instances for the Value of aeson.

A program that uses the yaml package can switch to yamlet in steps with this package. The document Coming from the yaml package shows how, and lists the differences between the two.

Example

A list of servers decodes with the FromJSON instance of the server type. Each server decodes on its own, so an error in one server does not hide the errors in the others:

{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE NoFieldSelectors #-}
{-# LANGUAGE OverloadedRecordDot #-}

import Data.Aeson qualified as A
import Data.Text (Text)
import Yamlet
import Yamlet.Aeson

data Server = Server {port :: Int, host :: Text}
  deriving stock (Generic, Show)
  deriving anyclass (A.FromJSON)

main :: IO ()
main = do
  result <- decodeFile @[ViaAeson Server] path
  case result of
    Left errs -> mapM_ (putStrLn . prettyError path) errs
    Right servers -> mapM_ (print . (.value)) servers
  where
    path :: FilePath
    path = "servers.yaml"

For this file:

- port: 80
  host: a.example.com
- port: 81
  host: b.example.com

the program prints the servers:

Server {port = 80, host = "a.example.com"}
Server {port = 81, host = "b.example.com"}

For this file:

- port: http
  host: a.example.com
- port: 81
- port: 82
  host: c.example.com

the program prints every error:

servers.yaml:1:9: [0].port: parsing Int failed, expected Number, but encountered String
  |
1 | - port: http
  |         ^
servers.yaml:3:3: [1]: parsing Main.Server(Server) failed, key "host" not found
  |
3 | - port: 81
  |   ^

Order of keys

The encoder writes the keys of a mapping in the order of toEncoding. The default toEncoding goes through toJSON, so the keys come in the order of an aeson object, which is sorted by default.

The decoder of aeson gets the keys in no order, because an aeson object has none. To keep the order of a mapping, a program decodes the mapping with a decoder of yamlet, e.g. with withMapping and objectEntries. Its values can still decode via ViaAeson.

Conversion

A YAML document converts to an aeson Value as follows:

  • A key is the text of its scalar, e.g. "0x10" for 0x10 and "~" for ~, as in the yaml package. Two keys with the same text are an error, e.g. 1 and "1". A key that is a collection is an error.
  • A key << is an ordinary key, because the merge keys of YAML 1.1 are not supported.
  • .inf and -.inf are the strings "+inf" and "-inf", and .nan is null, which the FromJSON and ToJSON instances for Double and Float read and write.
  • -0.0 is the number 0, because a Scientific has no negative zero.
  • A number whose exponent in scientific notation is beyond the range from -1000 to 1000, e.g. 1e1001, is an error, as in yamlet. A Number converts to YAML as aeson writes it in JSON: as an integer if its base10Exponent is from 0 to 1024, otherwise in scientific notation. Thus 1e1001 reads back as an integer, but 1e1025 and 1e-1001 do not read back.
  • A tag that is not of the core schema makes a scalar a string, e.g. !secret 123 is the string "123". The yaml package reads it as the number 123. A collection with such a tag converts as without it, e.g. !point {x: 1} is the object {"x": 1}.

A FromJSON instance can convert two different keys to the same key and then keep only one of the pairs, as it does for JSON, e.g. 1 and 1.0 for a Map Int. The FromYaml instances for maps reject such keys.

A Value converts to YAML as aeson writes it in JSON, e.g. the keys of a Map Int are strings, which the encoder quotes because they look like numbers.

Changes

yamlet-aeson-1.0.0.1 (2026-10-12)

  • Allow aeson 2.2.5.1.

yamlet-aeson-1.0.0.0 (2026-10-11)

  • Initial release.