Supports strict mode, where type fields and json fields must match
```nim
import pkg/serde/json
type MyType {.deserialize(mode=Strict).} = object
field1: int
field2: int
let jsn = """{
"field1": 1,
"field2": 2,
"extra": 3
}"""
let res = MyType.fromJson(jsn)
assert res.isFailure
assert res.error of SerdeError
assert res.error.msg == "json field(s) missing in object: {\"extra\"}"
```
## Serde modes
`nim-serde` uses three different modes to control de/serialization:
```nim
OptIn
OptOut
Strict
```
Modes can be set in the `{.serialize.}` and/or `{.deserialize.}` pragmas on type definitions. Each mode has a different meaning depending on if the type is being serialized or deserialized. Modes can be set by setting `mode` in the `serialize` or `deserialize` pragma annotation, eg:
| `SerdeMode.OptOut` | All object fields will be serialized, except fields marked with `{.serialize(ignore=true).}`. | All json keys will be deserialized, except fields marked with `{.deserialize(ignore=true).}`. No error if extra json fields exist. |
| `SerdeMode.OptIn` | Only fields marked with `{.serialize.}` will be serialized. Fields marked with `{.serialize(ignore=true).}` will not be serialized. | Only fields marked with `{.deserialize.}` will be deserialized. Fields marked with `{.deserialize(ignore=true).}` will not be deserialized. A `SerdeError` error is raised if the field is missing in json. |
| `SerdeMode.Strict` | All object fields will be serialized, regardless if the field is marked with `{.serialize(ignore=true).}`. | Object fields and json fields must match exactly, otherwise a `SerdeError` is raised. |
## Default modes
`nim-serde` will de/serialize types if they are not annotated with `serialize` or `deserialize`, but will assume a default mode. By default, with no pragmas specified, `serde` will always serialize in `OptIn` mode, meaning any fields to b Additionally, if the types are annotated, but a mode is not specified, `serde` will assume a (possibly different) default mode.
```nim
# Type is not annotated
# A default mode of OptIn (for serialize) and OptOut (for deserialize) is assumed.
type MyObj = object
field1: bool
field2: bool
# Type is annotated, but mode not specified
# A default mode of OptOut is assumed for both serialize and deserialize.
| Default (pragma, but no mode) | `OptOut` | `OptOut` |
## Serde field options
Type fields can be annotated with `{.serialize.}` and `{.deserialize.}` and properties can be set on these pragmas, determining de/serialization behavior.
Specifying a `key`, will alias the field name. When seriazlizing, json will be written with `key` instead of the field name. When deserializing, the json must contain `key` for the field to be deserialized.
### `ignore`
Specifying `ignore`, will prevent de/serialization on the field.
| `key` | aliases the field name in json | deserializes the field if json contains `key` |
| `ignore` | <li>**OptOut:** field not serialized</li><li>**OptIn:** field not serialized</li><li>**Strict:** field serialized</li> | <li>**OptOut:** field not deserialized</li><li>**OptIn:** field not deserialized</li><li>**Strict:** field deserialized</li> |
## Deserialization
`serde` deserializes using `fromJson`, and in all instances returns `Result[T, CatchableError]`, where `T` is the type being deserialized. For example:
`nim-serde` can be used as a drop-in replacement for the [standard library's `json` module](https://nim-lang.org/docs/json.html), with a few notable improvements.
Instead of importing `std/json` into your application, `pkg/serde/json` can be imported instead:
```diff
- import std/json
+ import pkg/serde/json
```
As with `std/json`, `%` can be used to serialize a type into a `JsonNode`:
```nim
import pkg/serde/json
assert %"hello" == newJString("hello")
```
And `%*` can be used to serialize objects:
```nim
import pkg/serde/json
let expected = newJObject()
expected["hello"] = newJString("world")
assert %*{"hello": "world"} == expected
```
As well, serialization of types can be overridden, and serialization of custom types can be introduced. Here, we are overriding the serialization of `int`:
```nim
import pkg/serde/json
func `%`(i: int): JsonNode =
newJInt(i + 1)
assert 1.toJson == "2"
```
## `parseJson` and exception tracking
Unfortunately, `std/json`'s `parseJson` can raise an `Exception`, so proper exception tracking breaks, eg
```nim
## Fails to compile:
## Error: parseJson(me, false, false) can raise an unlisted exception: Exception
This is due to `std/json`'s `parseJson` incorrectly raising `Exception`. This can be worked around by instead importing `serde` and calling its `parseJson`. Note that `serde`'s `parseJson` returns a `Result[JsonNode, CatchableError]` instead of just a plain `JsonNode` object: