aeson-generic-default: Type-level default fields for aeson Generic FromJSON parser

[ bsd3, json, library, text, web ] [ Propose Tags ] [ Report a vulnerability ]

Define default values for missing FromJSON object fields within field type declaration.

It becomes handy e.g. for parsing yaml configuration files. The default values are mostly defined directly at the type level so that the user doesn't have to write manual FromJSON instance.


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.1.0.0, 0.1.1.0
Change log CHANGELOG.md
Dependencies aeson (>=2.2 && <2.3), base (>=4.16 && <5), data-default (>=0.7 && <0.8), text (>=2.0 && <2.2) [details]
Tested with ghc ==9.2.8, ghc ==9.6.5, ghc ==9.10.1
License BSD-3-Clause
Author Ondrej Palkovsky
Maintainer palkovsky.ondrej@gmail.com
Category Text, Web, JSON
Home page https://github.com/ondrap/aeson-generic-default
Bug tracker https://github.com/ondrap/aeson-generic-default/issues
Uploaded by ondrap at 2024-10-09T10:33:10Z
Distributions
Downloads 42 total (9 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2024-10-09 [all 1 reports]

Readme for aeson-generic-default-0.1.1.0

[back to package description]

aeson-generic-default

Type-level configuration of missing values for aeson FromJSON Generic parser.

Using higher-kinded-types, Coercible and Generic instances it is possible to define a class that can be configured by a type parameter to use custom field parsers during parsing and only when the parsing is done, it can be coerced to use normal types.

data ConfigFileT d = ConfigFile {
  defaultEnabled :: DefaultField d (DefBool True)
, defaultDisabled :: DefaultField d (DefBool False)
, defaultText :: DefaultField d (DefText "default text")
, defaultInt :: DefaultField d (DefInt 42)
, defaultNegativeInt :: DefaultField d (DefNegativeInt 42)
, defaultRed :: DefaultField d (DefDefault Color)
, defaultBlue :: DefaultField d (DefDefaultConstant BlueDefault)
, normalField :: T.Text
, normalOptional :: Maybe Int
} deriving (Generic)
type ConfigFile = ConfigFileT Final

instance FromJSON ConfigFile where
  parseJSON = parseWithDefaults defaultOptions

The resulting ConfigFile type alias has a form of:

{
  defaultEnabled :: Bool
, defaultDisabled :: Bool
, defaultText :: Text
, defaultInt :: Int
, defaultNegativeInt :: Int
, defaultRed :: Color
, defaultBlue :: Color
, normalField :: T.Text
, normalOptional :: Maybe Int
}

The type-level configuration can be easily extended with newtypes, e.g. to create a full compatibility layer with singletons:

newtype DefSing (a :: k) = DefSing (Demote k) deriving Generic
instance (SingI a, SingKind k, FromJSON (Demote k)) => FromJSON (DefSing (a :: k)) where
  omittedField = Just $ DefSing $ fromSing (sing @a)
  parseJSON v = DefSing <$> parseJSON v

And then the definition of the field can be for any singleton (e.g. Bool):

flag :: DefaultField d (DefSing True)