mirror of
https://github.com/logos-storage/nim-serde.git
synced 2026-01-08 00:23:07 +00:00
Change parseJson to JsonNode.parse (#4)
* Change parseJson to JsonNode.parse Exporting `parseJson` causes symbol clashes in downstream repos that import std/json, so changing the signature completely avoid this clash. * Fix usages of parseJson, update README
This commit is contained in:
parent
6bd69489a7
commit
b04435fb88
43
README.md
43
README.md
@ -108,7 +108,10 @@ OptOut
|
|||||||
Strict
|
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:
|
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:
|
||||||
|
|
||||||
```nim
|
```nim
|
||||||
type MyType {.serialize(mode=Strict).} = object
|
type MyType {.serialize(mode=Strict).} = object
|
||||||
@ -126,7 +129,11 @@ type MyType {.serialize(mode=Strict).} = object
|
|||||||
|
|
||||||
## Default modes
|
## 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-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
|
```nim
|
||||||
# Type is not annotated
|
# Type is not annotated
|
||||||
@ -152,7 +159,8 @@ type MyObj {.serialize, deserialize.} = object
|
|||||||
| Default (pragma, but no mode) | `OptOut` | `OptOut` |
|
| Default (pragma, but no mode) | `OptOut` | `OptOut` |
|
||||||
|
|
||||||
## Serde field options
|
## Serde field options
|
||||||
Type fields can be annotated with `{.serialize.}` and `{.deserialize.}` and properties can be set on these pragmas, determining de/serialization behavior.
|
Type fields can be annotated with `{.serialize.}` and `{.deserialize.}` and properties
|
||||||
|
can be set on these pragmas, determining de/serialization behavior.
|
||||||
|
|
||||||
For example,
|
For example,
|
||||||
|
|
||||||
@ -192,7 +200,9 @@ assert !Person.fromJson(createResponse) == Person(id: 1)
|
|||||||
```
|
```
|
||||||
|
|
||||||
### `key`
|
### `key`
|
||||||
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.
|
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`
|
### `ignore`
|
||||||
Specifying `ignore`, will prevent de/serialization on the field.
|
Specifying `ignore`, will prevent de/serialization on the field.
|
||||||
@ -207,7 +217,8 @@ Specifying `ignore`, will prevent de/serialization on the field.
|
|||||||
|
|
||||||
## Deserialization
|
## Deserialization
|
||||||
|
|
||||||
`serde` deserializes using `fromJson`, and in all instances returns `Result[T, CatchableError]`, where `T` is the type being deserialized. For example:
|
`serde` deserializes using `fromJson`, and in all instances returns `Result[T,
|
||||||
|
CatchableError]`, where `T` is the type being deserialized. For example:
|
||||||
|
|
||||||
```nim
|
```nim
|
||||||
type MyType = object
|
type MyType = object
|
||||||
@ -266,7 +277,8 @@ func fromJson(_: type Address, json: JsonNode): ?!Address =
|
|||||||
|
|
||||||
## Serializing to string (`toJson`)
|
## Serializing to string (`toJson`)
|
||||||
|
|
||||||
`toJson` is a shortcut for serializing an object into its serialized string representation:
|
`toJson` is a shortcut for serializing an object into its serialized string
|
||||||
|
representation:
|
||||||
|
|
||||||
```nim
|
```nim
|
||||||
import pkg/serde/json
|
import pkg/serde/json
|
||||||
@ -289,9 +301,11 @@ return RestApiResponse.response(availability.toJson,
|
|||||||
|
|
||||||
## `std/json` drop-in replacment
|
## `std/json` drop-in replacment
|
||||||
|
|
||||||
`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.
|
`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:
|
Instead of importing `std/json` into your application, `pkg/serde/json` can be imported
|
||||||
|
instead:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
- import std/json
|
- import std/json
|
||||||
@ -316,7 +330,8 @@ expected["hello"] = newJString("world")
|
|||||||
assert %*{"hello": "world"} == expected
|
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`:
|
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
|
```nim
|
||||||
import pkg/serde/json
|
import pkg/serde/json
|
||||||
@ -329,7 +344,8 @@ assert 1.toJson == "2"
|
|||||||
|
|
||||||
## `parseJson` and exception tracking
|
## `parseJson` and exception tracking
|
||||||
|
|
||||||
Unfortunately, `std/json`'s `parseJson` can raise an `Exception`, so proper exception tracking breaks, eg
|
Unfortunately, `std/json`'s `parseJson` can raise an `Exception`, so proper exception
|
||||||
|
tracking breaks, eg
|
||||||
|
|
||||||
```nim
|
```nim
|
||||||
|
|
||||||
@ -352,7 +368,10 @@ proc parseMe(me: string): JsonNode =
|
|||||||
assert """{"hello":"world"}""".parseMe == %* { "hello": "world" }
|
assert """{"hello":"world"}""".parseMe == %* { "hello": "world" }
|
||||||
```
|
```
|
||||||
|
|
||||||
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:
|
This is due to `std/json`'s `parseJson` incorrectly raising `Exception`. This can be
|
||||||
|
worked around by instead importing `serde` and calling its `JsonNode.parse` routine.
|
||||||
|
Note that `serde`'s `JsonNode.parse` returns a `Result[JsonNode, CatchableError]`
|
||||||
|
instead of just a plain `JsonNode` object as in `std/json`'s `parseJson`:
|
||||||
|
|
||||||
```nim
|
```nim
|
||||||
import pkg/serde/json
|
import pkg/serde/json
|
||||||
@ -363,7 +382,7 @@ type
|
|||||||
MyAppError = object of CatchableError
|
MyAppError = object of CatchableError
|
||||||
|
|
||||||
proc parseMe(me: string): JsonNode {.raises: [MyAppError].} =
|
proc parseMe(me: string): JsonNode {.raises: [MyAppError].} =
|
||||||
without parsed =? me.parseJson, error:
|
without parsed =? JsonNode.parse(me), error:
|
||||||
raise newException(MyAppError, error.msg)
|
raise newException(MyAppError, error.msg)
|
||||||
parsed
|
parsed
|
||||||
|
|
||||||
|
|||||||
@ -229,8 +229,8 @@ proc fromJson*[T: ref object or object](_: type T, json: JsonNode): ?!T =
|
|||||||
|
|
||||||
success(res)
|
success(res)
|
||||||
|
|
||||||
proc fromJson*(_: type JsonNode, jsn: string): ?!JsonNode =
|
proc fromJson*(_: type JsonNode, json: string): ?!JsonNode =
|
||||||
return parser.parseJson(jsn)
|
return JsonNode.parse(json)
|
||||||
|
|
||||||
proc fromJson*[T: ref object or object](_: type T, bytes: openArray[byte]): ?!T =
|
proc fromJson*[T: ref object or object](_: type T, bytes: openArray[byte]): ?!T =
|
||||||
let json = string.fromBytes(bytes)
|
let json = string.fromBytes(bytes)
|
||||||
@ -238,6 +238,6 @@ proc fromJson*[T: ref object or object](_: type T, bytes: openArray[byte]): ?!T
|
|||||||
echo "typeof json after parse: ", typeof json
|
echo "typeof json after parse: ", typeof json
|
||||||
T.fromJson(json)
|
T.fromJson(json)
|
||||||
|
|
||||||
proc fromJson*[T: ref object or object](_: type T, jsn: string): ?!T =
|
proc fromJson*[T: ref object or object](_: type T, json: string): ?!T =
|
||||||
let jsn = ?parser.parseJson(jsn) # full qualification required in-module only
|
let jsn = ?JsonNode.parse(json) # full qualification required in-module only
|
||||||
T.fromJson(jsn)
|
T.fromJson(jsn)
|
||||||
|
|||||||
@ -6,8 +6,9 @@ import ./types
|
|||||||
|
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
proc parseJson*(json: string): ?!JsonNode =
|
proc parse*(_: type JsonNode, json: string): ?!JsonNode =
|
||||||
## fix for nim raising Exception
|
# Used as a replacement for `std/json.parseJson`. Will not raise Exception like in the
|
||||||
|
# standard library
|
||||||
try:
|
try:
|
||||||
return stdjson.parseJson(json).catch
|
return stdjson.parseJson(json).catch
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@ -49,7 +49,7 @@ suite "json serialization - deserialize":
|
|||||||
|
|
||||||
test "deserializes array to sequence":
|
test "deserializes array to sequence":
|
||||||
let expected = @[1, 2, 3]
|
let expected = @[1, 2, 3]
|
||||||
let json = !"[1,2,3]".parseJson
|
let json = !JsonNode.parse("[1,2,3]")
|
||||||
check !seq[int].fromJson(json) == expected
|
check !seq[int].fromJson(json) == expected
|
||||||
|
|
||||||
test "deserializes uints int.high or smaller":
|
test "deserializes uints int.high or smaller":
|
||||||
@ -71,11 +71,13 @@ suite "json serialization - deserialize":
|
|||||||
let expected = MyObj(mystring: "abc", myint: 123, myoption: some true)
|
let expected = MyObj(mystring: "abc", myint: 123, myoption: some true)
|
||||||
|
|
||||||
let json =
|
let json =
|
||||||
!"""{
|
!JsonNode.parse(
|
||||||
|
"""{
|
||||||
"mystring": "abc",
|
"mystring": "abc",
|
||||||
"myint": 123,
|
"myint": 123,
|
||||||
"myoption": true
|
"myoption": true
|
||||||
}""".parseJson
|
}"""
|
||||||
|
)
|
||||||
|
|
||||||
check !MyObj.fromJson(json) == expected
|
check !MyObj.fromJson(json) == expected
|
||||||
|
|
||||||
@ -87,10 +89,12 @@ suite "json serialization - deserialize":
|
|||||||
let expected = MyObj(mystring: "abc", mybool: true)
|
let expected = MyObj(mystring: "abc", mybool: true)
|
||||||
|
|
||||||
let json =
|
let json =
|
||||||
!"""{
|
!JsonNode.parse(
|
||||||
|
"""{
|
||||||
"mystring": "abc",
|
"mystring": "abc",
|
||||||
"mybool": true
|
"mybool": true
|
||||||
}""".parseJson
|
}"""
|
||||||
|
)
|
||||||
|
|
||||||
check !MyObj.fromJson(json) == expected
|
check !MyObj.fromJson(json) == expected
|
||||||
|
|
||||||
@ -102,11 +106,13 @@ suite "json serialization - deserialize":
|
|||||||
let expected = MyObj(mystring: "abc", mybool: true)
|
let expected = MyObj(mystring: "abc", mybool: true)
|
||||||
|
|
||||||
let json =
|
let json =
|
||||||
!"""{
|
!JsonNode.parse(
|
||||||
|
"""{
|
||||||
"mystring": "abc",
|
"mystring": "abc",
|
||||||
"mybool": true,
|
"mybool": true,
|
||||||
"extra": "extra"
|
"extra": "extra"
|
||||||
}""".parseJson
|
}"""
|
||||||
|
)
|
||||||
check !MyObj.fromJson(json) == expected
|
check !MyObj.fromJson(json) == expected
|
||||||
|
|
||||||
test "deserializes objects with less fields":
|
test "deserializes objects with less fields":
|
||||||
@ -117,9 +123,11 @@ suite "json serialization - deserialize":
|
|||||||
let expected = MyObj(mystring: "abc", mybool: false)
|
let expected = MyObj(mystring: "abc", mybool: false)
|
||||||
|
|
||||||
let json =
|
let json =
|
||||||
!"""{
|
!JsonNode.parse(
|
||||||
|
"""{
|
||||||
"mystring": "abc"
|
"mystring": "abc"
|
||||||
}""".parseJson
|
}"""
|
||||||
|
)
|
||||||
check !MyObj.fromJson(json) == expected
|
check !MyObj.fromJson(json) == expected
|
||||||
|
|
||||||
test "deserializes ref objects":
|
test "deserializes ref objects":
|
||||||
@ -130,10 +138,12 @@ suite "json serialization - deserialize":
|
|||||||
let expected = MyRef(mystring: "abc", myint: 1)
|
let expected = MyRef(mystring: "abc", myint: 1)
|
||||||
|
|
||||||
let json =
|
let json =
|
||||||
!"""{
|
!JsonNode.parse(
|
||||||
|
"""{
|
||||||
"mystring": "abc",
|
"mystring": "abc",
|
||||||
"myint": 1
|
"myint": 1
|
||||||
}""".parseJson
|
}"""
|
||||||
|
)
|
||||||
|
|
||||||
let deserialized = !MyRef.fromJson(json)
|
let deserialized = !MyRef.fromJson(json)
|
||||||
check deserialized.mystring == expected.mystring
|
check deserialized.mystring == expected.mystring
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user