https://github.com/fumieval/deriving-aeson
Scrap your hand-rolled aeson instances
https://github.com/fumieval/deriving-aeson
Last synced: about 1 year ago
JSON representation
Scrap your hand-rolled aeson instances
- Host: GitHub
- URL: https://github.com/fumieval/deriving-aeson
- Owner: fumieval
- License: bsd-3-clause
- Created: 2020-02-26T07:29:42.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2024-11-23T02:29:14.000Z (over 1 year ago)
- Last Synced: 2025-03-29T14:06:46.927Z (about 1 year ago)
- Language: Haskell
- Homepage: http://hackage.haskell.org/package/deriving-aeson
- Size: 250 KB
- Stars: 112
- Watchers: 6
- Forks: 8
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
deriving-aeson
====
[](https://hackage.haskell.org/package/deriving-aeson)

[](https://discord.gg/DG93Tgs)

This package provides a newtype wrapper where you can customise
[aeson](https://hackage.haskell.org/package/aeson)'s generic methods using a
type-level interface, which synergises well with DerivingVia.
```haskell
{-# LANGUAGE DerivingVia, DataKinds, DeriveGeneric #-}
import Data.Aeson
import Deriving.Aeson
import qualified Data.ByteString.Lazy.Char8 as BL
data User = User
{ userId :: Int
, userName :: String
, userAPIToken :: Maybe String
} deriving Generic
deriving (FromJSON, ToJSON)
via CustomJSON '[OmitNothingFields, FieldLabelModifier '[StripPrefix "user", CamelToSnake]] User
testData :: [User]
testData = [User 42 "Alice" Nothing, User 43 "Bob" (Just "xyz")]
main = BL.putStrLn $ encode testData
-- [{"name":"Alice","id":42},{"api_token":"xyz","name":"Bob","id":43}]
```
`Deriving.Aeson.Stock` contains some aliases for even less boilerplates.
* `Prefixed str` = `CustomJSON '[FieldLabelModifier (StripPrefix str)]`
* `PrefixedSnake str` = `CustomJSON '[FieldLabelModifier (StripPrefix str, CamelToSnake)]`
* `Suffixed str` = `CustomJSON '[FieldLabelModifier (StripSuffix str)]`
* `SuffixedSnake str` = `CustomJSON '[FieldLabelModifier (StripSuffix str, CamelToSnake)]`
* `Snake` = `CustomJSON '[FieldLabelModifier '[StripPrefix str, CamelToSnake]]`
* `Vanilla` = `CustomJSON '[]`
How it works
----
The wrapper type has a phantom type parameter `t`, a type-level builder of an [Option](http://hackage.haskell.org/package/aeson-1.4.6.0/docs/Data-Aeson.html#t:Options).
Type-level primitives are reduced to one `Option` by the `AesonOptions` class.
```haskell
newtype CustomJSON t a = CustomJSON { unCustomJSON :: a }
class AesonOptions xs where
aesonOptions :: Options
instance AesonOptions xs => AesonOptions (OmitNothingFields ': xs) where
aesonOptions = (aesonOptions @xs) { omitNothingFields = True }
...
```
You can use any (static) function for name modification by adding an instance of `StringModifier`.
```haskell
data ToLower
instance StringModifier ToLower where
getStringModifier "" = ""
getStringModifier (c : xs) = toLower c : xs
```
Previous studies
----
* [Type-driven safe derivation of ToJSON and FromJSON, using DerivingVia in GHC 8.6 and some type-level hacks](https://gist.github.com/konn/27c00f784dd883ec2b90eab8bc84a81d)
* [Strip prefices from JSON representation](https://gist.github.com/fumieval/5c89205d418d5f9cafac801afbe94969)