File: README.md

package info (click to toggle)
haskell-deriving-aeson 0.2.10-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 76 kB
  • sloc: haskell: 228; makefile: 3
file content (75 lines) | stat: -rw-r--r-- 2,858 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
deriving-aeson
====

[![Hackage](https://img.shields.io/hackage/v/deriving-aeson.svg)](https://hackage.haskell.org/package/deriving-aeson)
![Haskell CI](https://github.com/fumieval/deriving-aeson/workflows/Haskell%20CI/badge.svg)
[![Discord](https://img.shields.io/discord/664807830116892674?color=%237095ec&label=Discord&style=plastic)](https://discord.gg/DG93Tgs)

![logo](https://github.com/fumieval/deriving-aeson/blob/master/logo/logo.png?raw=true)

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)