nim-serde/README.md
munna0908 2d8fa4d940
Apply suggestions from code review
Co-authored-by: Giuliano Mega <giuliano.mega@gmail.com>
2025-06-17 12:37:17 +05:30

132 lines
3.7 KiB
Markdown

# nim-serde
A serialization and deserialization library for Nim supporting multiple formats.
## Supported Serialization Formats
nim-serde currently supports the following serialization formats:
- **JSON**: A text-based data interchange format. [See JSON](serde/json/README.md) for details.
- **CBOR**: A binary data format following RFC 8949. [See CBOR](serde/cbor/README.md) for details.
## Quick Examples
### JSON Serialization and Deserialization
```nim
import ./serde/json
import questionable/results
# Define a type
type Person = object
name {.serialize.}: string
age {.serialize.}: int
address: string # By default, serde will not serialize non-annotated fields (OptIn mode)
# Create an instance
let person = Person(name: "John Doe", age: 30, address: "123 Main St")
# Serialization
echo "JSON Serialization Example"
let jsonString = person.toJson(pretty = true)
echo jsonString
# Verify serialization output
let expectedJson = """{
"name": "John Doe",
"age": 30
}"""
assert jsonString == expectedJson
# Deserialization
echo "\nJSON Deserialization Example"
let jsonData = """{"name":"Jane Doe","age":28,"address":"456 Oak Ave"}"""
let result = Person.fromJson(jsonData)
# check if deserialization was successful
assert result.isSuccess
# get the deserialized value
let parsedPerson = !result
echo parsedPerson
#[
Expected Output:
Person(
name: "Jane Doe",
age: 28,
address: "456 Oak Ave"
)
]#
```
### CBOR Serialization and Deserialization
```nim
import ./serde/cbor
import questionable/results
import std/streams
# Define a type
type Person = object
name: string # Unlike JSON, CBOR always serializes all fields, and they do not need to be annotated
age: int
address: string
# Create an instance
let person = Person(name: "John Doe", age: 30, address: "123 Main St")
# Serialization using Stream API
echo "CBOR Stream API Serialization"
let stream = newStringStream()
let writeResult = stream.writeCbor(person)
assert writeResult.isSuccess
# Serialization using toCbor function
echo "\nCBOR toCbor Function Serialization"
let cborResult = toCbor(person)
assert cborResult.isSuccess
let serializedCbor = !cborResult
# Deserialization
echo "\nCBOR Deserialization"
let personResult = Person.fromCbor(serializedCbor)
# check if deserialization was successful
assert personResult.isSuccess
# get the deserialized value
let parsedPerson = !personResult
echo parsedPerson
#[
Expected Output:
Person(
name: "John Doe",
age: 30,
address: "123 Main St"
)
]#
```
Refer to the [json](serde/json/README.md) and [cbor](serde/cbor/README.md) files for more comprehensive examples.
## Known Issues
There is a known issue when using mixins with generic overloaded procs like `fromJson`. At the time of mixin call, only the `fromJson` overloads in scope of the called mixin are available to be dispatched at runtime. There could be other `fromJson` overloads declared in other modules, but are not in scope at the time the mixin was called.
Therefore, anytime `fromJson` is called targeting a declared overload, it may or may not be dispatchable. This can be worked around by forcing the `fromJson` overload into scope at compile time. For example, in your application where the `fromJson` overload is defined, at the bottom of the module add:
```nim
static: MyType.fromJson("")
```
This will ensure that the `MyType.fromJson` overload is dispatchable.
The basic types that serde supports should already have their overloads forced in scope in [the `deserializer` module](./serde/json/deserializer.nim#L340-L356).
For an illustration of the problem, please see this [narrow example](https://github.com/gmega/serialization-bug/tree/main/narrow) by [@gmega](https://github.com/gmega).