I'm making a small web service in Nim, and I need to respond to requests with json. I'm using the jester module to make the service. I expect I can use the json module in Nim's base library to construct some kind of object with fields and values, and then convert it to a json string. But how? Or is there a better way to construct json in Nim?
4 Answers
The marshal module includes a generic object-to-json serialisation algorithm that works for any type (currently, it uses run-time type introspection).
import marshal
type
Person = object
age: int
name: string
var p = Person(age: 38, name: "Torbjørn")
echo($$p)
The output will be:
{"age": 38, "name": "Torbj\u00F8rn"}

- 5,314
- 1
- 34
- 31
-
While Grzegorz answer was just what I was looking for, this answer was also very usefull, interesting, and simpler than using the json module. Cool! – Torbjørn Oct 04 '14 at 22:01
-
1It seems that in Nim everyone makes operators? – PascalVKooten Jun 29 '17 at 23:35
-
6This is **not** how you should serialise to JSON in Nim. The `marshal` module is Python's equivalent to `pickle`, the fact that it uses JSON as its serialisation format is a pure coincidence, do not use it to serialise objects to JSON. This is especially something you shouldn't do now that the `json` module supports effectively the same thing: https://play.nim-lang.org/#ix=2uPe – dom96 Aug 21 '20 at 16:17
In Nim you use the json module to create JsonNode
objects which are object variants. These can be constructed with the individual procs like newJObject() and then populate the fields
sequence. Another quicker way is to use the %() proc which accepts a sequence of tuples where one value is the string with the json field and the other the individual JsonNode
.
Here's an example showing both ways:
import json
type
Person = object ## Our generic person record.
age: int ## The age of the person.
name: string ## The name of the person.
proc `%`(p: Person): JsonNode =
## Quick wrapper around the generic JObject constructor.
result = %[("age", %p.age), ("name", %p.name)]
proc myCustomJson(p: Person): JsonNode =
## Custom method where we replicate manual construction.
result = newJObject()
# Initialize empty sequence with expected field tuples.
var s: seq[tuple[key: string, val: JsonNode]] = @[]
# Add the integer field tuple to the sequence of values.
s.add(("age", newJInt(p.age)))
# Add the string field tuple to the sequence of values.
s.add(("name", newJString(p.name)))
result.fields = s
proc test() =
# Tests making some jsons.
var p: Person
p.age = 24
p.name = "Minah"
echo(%p) # { "age": 24, "name": "Minah"}
p.age = 33
p.name = "Sojin"
echo(%p) # { "age": 33, "name": "Sojin"}
p.age = 40
p.name = "Britney"
echo p.myCustomJson # { "age": 40, "name": "Britney"}
when isMainModule: test()

- 7,349
- 1
- 36
- 78
-
2Sorry, but that's a terrible way to generate JSON, nobody these days generates it by manually writing serialisation functions – Alex Craft Aug 19 '20 at 18:00
-
Please see the discussion at https://forum.nim-lang.org/t/6707 about this incorrect answer. – Jim Balter Aug 21 '20 at 23:10
For anyone else finding the marshal
-based answer in this thread. Use this instead:
import json
type
Person = object
age: int
name: string
var p = Person(age: 38, name: "Torbjørn")
echo(%p)
Note that you should not be using marshal
for this purpose, it is the equivalent of the pickle
module in Python and it may generate JSON that has extra data that you likely don't want. Also, right now it's just a coincidence that it generates JSON, it may choose a different format in the future.

- 1,012
- 1
- 9
- 22
-
as a Nim newbie... what is going on here? in what circumstances does `echo(%p)` "just work" for your data structure, or fail? presumably if your `Person` type has attributes which aren't `string` or `int` then you will have to do some more work - what would be an idiomatic Nim way to handle that? – Anentropic Aug 21 '20 at 18:08
-
so the `%` in `%p` is this generic proc from `json` module? https://nim-lang.org/docs/json.html#%25%2Cstring Does that mean you could implement your own specialization (is that the right terminology?) of `%` to handle other data types, eg to serialize `DateTime -> string` for example? – Anentropic Aug 21 '20 at 18:17
-
2well, I just tried it and exactly that works https://play.nim-lang.org/#ix=2uPX ...this is nice – Anentropic Aug 21 '20 at 18:29
-
@Anentropic `echo` implicitly calls `$` on its arguments (see the documentation for `echo`). `$` is Nim's "toString" function. So just implement `$` for your datatype and you can print its string representation. `%` returns a `JsonNode`, and `$` is implemented for `JsonNode`, so `echo %p` (or `echo $ %p`) works. Pretty straightforward, really. "presumably if your Person type has attributes which aren't string or int then you will have to do some more work " -- sure ... the implementer of the json module did that work. (And `int` isn't special -- `$` for `int` is provided by the Nim library.) – Jim Balter Aug 21 '20 at 23:16
-
Ah I didn't notice `$` is involved too. The json module provides implementations of `%` covering the basic types which easily translate to json (numbers, strings, sequences, hash-tables and objects), for any other types you have to provide your own implementation (as we'd expect) otherwise you get a compile error when you `echo(%p)`. – Anentropic Aug 21 '20 at 23:40
-
@Anentropic "otherwise you get a compile error when you echo(%p)" -- you get a compilation error when you refer to `%p`, period ... `echo` has nothing to do with it. `echo %p` is effectively `stdout.writeln $(%p)`. If there's no `%` in scope defined to take an argument of `p` 's type, then of course that's an error. Again, this is all quite straightforward, and isn't speciflc to `json`, `%`, `echo`, etc. – Jim Balter Aug 26 '20 at 06:40
-
1
Do the following:
import json
var jsonResponse = %*
{"data": [{ "id": 35,
"type": "car",
"attributes": {"color":"red"} }]}
var body = ""
toUgly(body, jsonResponse)
echo body

- 1,726
- 16
- 32