# json

Dark Mode

- Manual
- Standard library
- Index
- devel, stable

Search:
Group by:

This module implements a simple high performance JSON parser. JSON (JavaScript Object Notation) is a lightweight data-interchange format that is easy for humans to read and write (unlike XML). It is easy for machines to parse and generate. JSON is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999.

# Overview

## Parsing JSON

JSON often arrives into your program (via an API or a file) as a `string`. The first step is to change it from its serialized form into a nested object structure called a `JsonNode`.

The `parseJson` procedure takes a string containing JSON and returns a `JsonNode` object. This is an object variant and it is either a `JObject`, `JArray`, `JString`, `JInt`, `JFloat`, `JBool` or `JNull`. You check the kind of this object variant by using the `kind` accessor.

For a `JsonNode` who's kind is `JObject`, you can access its fields using the `[]` operator. The following example shows how to do this:

    import json

    let jsonNode = parseJson("""{"key": 3.14}""")

    doAssert jsonNode.kind == JObject
    doAssert jsonNode["key"].kind == JFloat

## Reading values

Once you have a `JsonNode`, retrieving the values can then be achieved by using one of the helper procedures, which include:

- `getInt`
- `getFloat`
- `getStr`
- `getBool`

To retrieve the value of `"key"` you can do the following:

    import json

    let jsonNode = parseJson("""{"key": 3.14}""")

    doAssert jsonNode["key"].getFloat() == 3.14

Important: The `[]` operator will raise an exception when the specified field does not exist.

## Handling optional keys

By using the `{}` operator instead of `[]`, it will return `nil` when the field is not found. The `get`-family of procedures will return a type's default value when called on `nil`.

    import json

    let jsonNode = parseJson("{}")

    doAssert jsonNode{"nope"}.getInt() == 0
    doAssert jsonNode{"nope"}.getFloat() == 0
    doAssert jsonNode{"nope"}.getStr() == ""
    doAssert jsonNode{"nope"}.getBool() == false

## Using default values

The `get`-family helpers also accept an additional parameter which allow you to fallback to a default value should the key's values be `null`:

    import json

    let jsonNode = parseJson("""{"key": 3.14, "key2": null}""")

    doAssert jsonNode["key"].getFloat(6.28) == 3.14
    doAssert jsonNode["key2"].getFloat(3.14) == 3.14
    doAssert jsonNode{"nope"}.getFloat(3.14) == 3.14 # note the {}

## Unmarshalling

In addition to reading dynamic data, Nim can also unmarshal JSON directly into a type with the `to` macro.

    import json

    type
      User = object
        name: string
        age: int

    let userJson = parseJson("""{ "name": "Nim", "age": 12 }""")
    let user = to(userJson, User)

# Creating JSON

This module can also be used to comfortably create JSON using the `%*` operator:

    import json

    var hisName = "John"
    let herAge = 31
    var j = %*
      [
        { "name": hisName, "age": 30 },
        { "name": "Susan", "age": herAge }
      ]

    var j2 = %* {"name": "Isaac", "books": ["Robot Dreams"]}
    j2["details"] = %* {"age":35, "pi":3.1415}
    echo j2

Examples:

    ## Note: for JObject, key ordering is preserved, unlike in some languages,
    ## this is convenient for some use cases. Example:
    type
      Foo = object
        a1, a2, a0, a3, a4: int

    doAssert $(%*Foo()) == """{"a1":0,"a2":0,"a0":0,"a3":0,"a4":0}"""

# Imports

hashes, tables, strutils, lexbase, streams, macros, parsejson, options

# Types

    JsonNodeKind = enum
      JNull, JBool, JInt, JFloat, JString, JObject, JArray

  possible JSON node types Source Edit

    JsonNode = ref JsonNodeObj

  JSON node Source Edit

    JsonNodeObj {...}{.acyclic.} = object
      case kind*: JsonNodeKind
      of JString:
          str*: string

      of JInt:
          num*: BiggestInt

      of JFloat:
          fnum*: float

      of JBool:
          bval*: bool

      of JNull:
          nil

      of JObject:
          fields*: OrderedTable[string, JsonNode]

      of JArray:
          elems*: seq[JsonNode]

  Source Edit

# Procs

    proc newJString(s: string): JsonNode {...}{.raises: [], tags: [].}

  Creates a new `JString JsonNode`. Source Edit

    proc newJInt(n: BiggestInt): JsonNode {...}{.raises: [], tags: [].}

  Creates a new `JInt JsonNode`. Source Edit

    proc newJFloat(n: float): JsonNode {...}{.raises: [], tags: [].}

  Creates a new `JFloat JsonNode`. Source Edit

    proc newJBool(b: bool): JsonNode {...}{.raises: [], tags: [].}

  Creates a new `JBool JsonNode`. Source Edit

    proc newJNull(): JsonNode {...}{.raises: [], tags: [].}

  Creates a new `JNull JsonNode`. Source Edit

    proc newJObject(): JsonNode {...}{.raises: [], tags: [].}

  Creates a new `JObject JsonNode` Source Edit

    proc newJArray(): JsonNode {...}{.raises: [], tags: [].}

  Creates a new `JArray JsonNode` Source Edit

    proc getStr(n: JsonNode; default: string = ""): string {...}{.raises: [], tags: [].}

  Retrieves the string value of a `JString JsonNode`.

  Returns `default` if `n` is not a `JString`, or if `n` is nil.

  Source Edit

    proc getInt(n: JsonNode; default: int = 0): int {...}{.raises: [], tags: [].}

  Retrieves the int value of a `JInt JsonNode`.

  Returns `default` if `n` is not a `JInt`, or if `n` is nil.

  Source Edit

    proc getBiggestInt(n: JsonNode; default: BiggestInt = 0): BiggestInt {...}{.
        raises: [], tags: [].}

  Retrieves the BiggestInt value of a `JInt JsonNode`.

  Returns `default` if `n` is not a `JInt`, or if `n` is nil.

  Source Edit

    proc getFloat(n: JsonNode; default: float = 0.0): float {...}{.raises: [], tags: [].}

  Retrieves the float value of a `JFloat JsonNode`.

  Returns `default` if `n` is not a `JFloat` or `JInt`, or if `n` is nil.

  Source Edit

    proc getBool(n: JsonNode; default: bool = false): bool {...}{.raises: [], tags: [].}

  Retrieves the bool value of a `JBool JsonNode`.

  Returns `default` if `n` is not a `JBool`, or if `n` is nil.

  Source Edit

    proc getFields(n: JsonNode; default = initOrderedTable(4)): OrderedTable[string,
        JsonNode] {...}{.raises: [], tags: [].}

  Retrieves the key, value pairs of a `JObject JsonNode`.

  Returns `default` if `n` is not a `JObject`, or if `n` is nil.

  Source Edit

    proc getElems(n: JsonNode; default: seq[JsonNode] = @[]): seq[JsonNode] {...}{.
        raises: [], tags: [].}

  Retrieves the array of a `JArray JsonNode`.

  Returns `default` if `n` is not a `JArray`, or if `n` is nil.

  Source Edit

    proc add(father, child: JsonNode) {...}{.raises: [], tags: [].}

  Adds `child` to a JArray node `father`. Source Edit

    proc add(obj: JsonNode; key: string; val: JsonNode) {...}{.raises: [], tags: [].}

  Sets a field from a `JObject`. Source Edit

    proc `%`(s: string): JsonNode {...}{.raises: [], tags: [].}

  Generic constructor for JSON data. Creates a new `JString JsonNode`. Source Edit

    proc `%`(n: uint): JsonNode {...}{.raises: [], tags: [].}

  Generic constructor for JSON data. Creates a new `JInt JsonNode`. Source Edit

    proc `%`(n: int): JsonNode {...}{.raises: [], tags: [].}

  Generic constructor for JSON data. Creates a new `JInt JsonNode`. Source Edit

    proc `%`(n: BiggestUInt): JsonNode {...}{.raises: [], tags: [].}

  Generic constructor for JSON data. Creates a new `JInt JsonNode`. Source Edit

    proc `%`(n: BiggestInt): JsonNode {...}{.raises: [], tags: [].}

  Generic constructor for JSON data. Creates a new `JInt JsonNode`. Source Edit

    proc `%`(n: float): JsonNode {...}{.raises: [], tags: [].}

  Generic constructor for JSON data. Creates a new `JFloat JsonNode`. Source Edit

    proc `%`(b: bool): JsonNode {...}{.raises: [], tags: [].}

  Generic constructor for JSON data. Creates a new `JBool JsonNode`. Source Edit

    proc `%`(keyVals: openArray[tuple[key: string, val: JsonNode]]): JsonNode {...}{.
        raises: [], tags: [].}

  Generic constructor for JSON data. Creates a new `JObject JsonNode` Source Edit

    proc `%`[T](elements: openArray[T]): JsonNode

  Generic constructor for JSON data. Creates a new `JArray JsonNode` Source Edit

    proc `%`[T](table: Table[string, T] | OrderedTable[string, T]): JsonNode

  Generic constructor for JSON data. Creates a new `JObject JsonNode`. Source Edit

    proc `%`[T](opt: Option[T]): JsonNode

  Generic constructor for JSON data. Creates a new `JNull JsonNode` if `opt` is empty, otherwise it delegates to the underlying value. Source Edit

    proc `[]=`(obj: JsonNode; key: string; val: JsonNode) {...}{.inline, raises: [],
        tags: [].}

  Sets a field from a `JObject`. Source Edit

    proc `%`[T: object](o: T): JsonNode

  Construct JsonNode from tuples and objects. Source Edit

    proc `%`(o: ref object): JsonNode

  Generic constructor for JSON data. Creates a new `JObject JsonNode` Source Edit

    proc `%`(o: enum): JsonNode

  Construct a JsonNode that represents the specified enum value as a string. Creates a new `JString JsonNode`. Source Edit

    proc `==`(a, b: JsonNode): bool {...}{.raises: [KeyError], tags: [].}

  Check two nodes for equality Source Edit

    proc hash(n: JsonNode): Hash {...}{.raises: [Exception], tags: [RootEffect].}

  Compute the hash for a JSON node Source Edit

    proc hash(n: OrderedTable[string, JsonNode]): Hash {...}{.noSideEffect,
        raises: [Exception], tags: [RootEffect].}

  Source Edit

    proc len(n: JsonNode): int {...}{.raises: [], tags: [].}

  If `n` is a `JArray`, it returns the number of elements. If `n` is a `JObject`, it returns the number of pairs. Else it returns 0. Source Edit

    proc `[]`(node: JsonNode; name: string): JsonNode {...}{.inline, raises: [KeyError],
        tags: [].}

  Gets a field from a `JObject`, which must not be nil. If the value at `name` does not exist, raises KeyError. Source Edit

    proc `[]`(node: JsonNode; index: int): JsonNode {...}{.inline, raises: [], tags: [].}

  Gets the node at `index` in an Array. Result is undefined if `index` is out of bounds, but as long as array bound checks are enabled it will result in an exception. Source Edit

    proc hasKey(node: JsonNode; key: string): bool {...}{.raises: [], tags: [].}

  Checks if `key` exists in `node`. Source Edit

    proc contains(node: JsonNode; key: string): bool {...}{.raises: [], tags: [].}

  Checks if `key` exists in `node`. Source Edit

    proc contains(node: JsonNode; val: JsonNode): bool {...}{.raises: [KeyError],
        tags: [].}

  Checks if `val` exists in array `node`. Source Edit

    proc `{}`(node: JsonNode; keys: varargs[string]): JsonNode {...}{.raises: [],
        tags: [].}

  Traverses the node and gets the given value. If any of the keys do not exist, returns `nil`. Also returns `nil` if one of the intermediate data structures is not an object.

  This proc can be used to create tree structures on the fly (sometimes called autovivification):

      myjson{"parent", "child", "grandchild"} = newJInt(1)

  Source Edit

    proc `{}`(node: JsonNode; index: varargs[int]): JsonNode {...}{.raises: [], tags: [].}

  Traverses the node and gets the given value. If any of the indexes do not exist, returns `nil`. Also returns `nil` if one of the intermediate data structures is not an array. Source Edit

    proc getOrDefault(node: JsonNode; key: string): JsonNode {...}{.raises: [], tags: [].}

  Gets a field from a `node`. If `node` is nil or not an object or value at `key` does not exist, returns nil Source Edit

    proc `{}`(node: JsonNode; key: string): JsonNode {...}{.raises: [], tags: [].}

  Gets a field from a `node`. If `node` is nil or not an object or value at `key` does not exist, returns nil Source Edit

    proc `{}=`(node: JsonNode; keys: varargs[string]; value: JsonNode) {...}{.
        raises: [KeyError], tags: [].}

  Traverses the node and tries to set the value at the given location to `value`. If any of the keys are missing, they are added. Source Edit

    proc delete(obj: JsonNode; key: string) {...}{.raises: [KeyError], tags: [].}

  Deletes `obj[key]`. Source Edit

    proc copy(p: JsonNode): JsonNode {...}{.raises: [], tags: [].}

  Performs a deep copy of `a`. Source Edit

    proc escapeJsonUnquoted(s: string; result: var string) {...}{.raises: [], tags: [].}

  Converts a string `s` to its JSON representation without quotes. Appends to `result`. Source Edit

    proc escapeJsonUnquoted(s: string): string {...}{.raises: [], tags: [].}

  Converts a string `s` to its JSON representation without quotes. Source Edit

    proc escapeJson(s: string; result: var string) {...}{.raises: [], tags: [].}

  Converts a string `s` to its JSON representation with quotes. Appends to `result`. Source Edit

    proc escapeJson(s: string): string {...}{.raises: [], tags: [].}

  Converts a string `s` to its JSON representation with quotes. Source Edit

    proc pretty(node: JsonNode; indent = 2): string {...}{.raises: [], tags: [].}

  Returns a JSON Representation of `node`, with indentation and on multiple lines.

  Similar to prettyprint in Python.

  Examples:

      let j = %*{"name": "Isaac", "books": ["Robot Dreams"],
                 "details": {"age": 35, "pi": 3.1415}}
      doAssert pretty(j) ==
          """{
        "name": "Isaac",
        "books": [
          "Robot Dreams"
        ],
        "details": {
          "age": 35,
          "pi": 3.1415
        }
      }"""

  Source Edit

    proc toUgly(result: var string; node: JsonNode) {...}{.raises: [], tags: [].}

  Converts `node` to its JSON Representation, without regard for human readability. Meant to improve `$` string conversion performance.

  JSON representation is stored in the passed `result`

  This provides higher efficiency than the `pretty` procedure as it does not attempt to format the resulting JSON to make it human readable.

  Source Edit

    proc `$`(node: JsonNode): string {...}{.raises: [], tags: [].}

  Converts `node` to its JSON Representation on one line. Source Edit

    proc parseJson(s: Stream; filename: string = ""): JsonNode {...}{.raises: [Defect,
        IOError, OSError, Defect, IOError, OSError, ValueError, JsonParsingError,
        Exception], tags: [ReadIOEffect, WriteIOEffect].}

  Parses from a stream `s` into a `JsonNode`. `filename` is only needed for nice error messages. If `s` contains extra data, it will raise `JsonParsingError`. This closes the stream `s` after it's done. Source Edit

    proc parseJson(buffer: string): JsonNode {...}{.raises: [Defect, IOError, OSError,
        ValueError, JsonParsingError, Exception],
        tags: [ReadIOEffect, WriteIOEffect].}

  Parses JSON from `buffer`. If `buffer` contains extra data, it will raise `JsonParsingError`. Source Edit

    proc parseFile(filename: string): JsonNode {...}{.raises: [IOError, Defect, OSError,
        ValueError, JsonParsingError, Exception],
        tags: [ReadIOEffect, WriteIOEffect].}

  Parses `file` into a `JsonNode`. If `file` contains extra data, it will raise `JsonParsingError`. Source Edit

    proc to[T](node: JsonNode; t: typedesc[T]): T

  Unmarshals the specified node into the object type specified.

  Known limitations:

  > - Heterogeneous arrays are not supported.
  > - Sets in object variants are not supported.
  > - Not nil annotations are not supported.

  Example:

      let jsonNode = parseJson("""
         {
           "person": {
             "name": "Nimmer",
             "age": 21
           },
           "list": [1, 2, 3, 4]
         }
      """)

      type
        Person = object
          name: string
          age: int

        Data = object
          person: Person
          list: seq[int]

      var data = to(jsonNode, Data)
      doAssert data.person.name == "Nimmer"
      doAssert data.person.age == 21
      doAssert data.list == @[1, 2, 3, 4]

  Source Edit

# Iterators

    iterator items(node: JsonNode): JsonNode {...}{.raises: [], tags: [].}

  Iterator for the items of `node`. `node` has to be a JArray. Source Edit

    iterator mitems(node: var JsonNode): var JsonNode {...}{.raises: [], tags: [].}

  Iterator for the items of `node`. `node` has to be a JArray. Items can be modified. Source Edit

    iterator pairs(node: JsonNode): tuple[key: string, val: JsonNode] {...}{.raises: [],
        tags: [].}

  Iterator for the child elements of `node`. `node` has to be a JObject. Source Edit

    iterator keys(node: JsonNode): string {...}{.raises: [], tags: [].}

  Iterator for the keys in `node`. `node` has to be a JObject. Source Edit

    iterator mpairs(node: var JsonNode): tuple[key: string, val: var JsonNode] {...}{.
        raises: [], tags: [].}

  Iterator for the child elements of `node`. `node` has to be a JObject. Values can be modified Source Edit

    iterator parseJsonFragments(s: Stream; filename: string = ""): JsonNode {...}{.raises: [
        Defect, IOError, OSError, Defect, IOError, OSError, ValueError,
        JsonParsingError, Exception], tags: [ReadIOEffect, WriteIOEffect].}

  Parses from a stream `s` into `JsonNodes`. `filename` is only needed for nice error messages. The JSON fragments are separated by whitespace. This can be substantially faster than the comparable loop `for x in splitWhitespace(s): yield parseJson(x)`. This closes the stream `s` after it's done. Source Edit

# Macros

    macro `%*`(x: untyped): untyped

  Convert an expression to a JsonNode directly, without having to specify `%` for every element. Source Edit

# Templates

    template `%`(j: JsonNode): JsonNode

  Source Edit

# Exports

$, $, $, $, $, $, JsonEventKind, JsonError, JsonParser, JsonKindError, open, open, open, open, open, close, close, close, close, str, getInt, getFloat, kind, kind, getColumn, getLine, getFilename, errorMsg, errorMsgExpected, next, JsonParsingError, raiseParseErr