Skip to content
Kavachकवच

JSON: Building

● Intermediate4 min

Where a Json is expected, ordinary literals become JSON; json.stringify writes any value as JSON text.

use std.json

type Point {
    x: Int
    y: Int
}

fn main() {
    const order: Json = [
        "id": 1042,
        "items": ["pen", "ink"],
        "paid": true,
        "note": none,
    ]
    print(order)
    print(json.stringify(Point(x: 1, y: 2)))
}

The program ran and printed:

kavach run build.kav

{"id":1042,"items":["pen","ink"],"paid":true,"note":null}{"x":1,"y":2}
build.kav: Kavach code, then what running it prints

none becomes null. A record is written with its fields in the order they are declared:

use std.json

type Item {
    name: String
    price: Int
}

fn main() {
    const cart = [Item(name: "pen", price: 20), Item(name: "ink", price: 45)]
    print(json.stringify(cart))
    print(json.stringify(cart, indent: 2))
}

The program ran and printed:

kavach run pretty.kav

[{"name":"pen","price":20},{"name":"ink","price":45}][  {    "name": "pen",    "price": 20  },  {    "name": "ink",    "price": 45  }]
pretty.kav: Kavach code, then what running it prints

How each type is written

use std.json

type Status = Pending | Paid(amount: Decimal)

type Example {
    whole: Int
    decimal: Float
    money: Decimal
    yes: Bool
    letter: Char
    text: String
    list: [Int]
    map: [String: Int]
    missing: String?
    pending: Status
    paid: Status
}

fn main() {
    const e = Example(
        whole: 42,
        decimal: 2.5,
        money: 19.99,
        yes: true,
        letter: 'k',
        text: "Asha",
        list: [1, 2],
        map: ["a": 1],
        missing: none,
        pending: Status.Pending,
        paid: Status.Paid(amount: 5.00),
    )
    print(json.stringify(e, indent: 2))
}

The program ran and printed:

kavach run types.kav

{  "whole": 42,  "decimal": 2.5,  "money": 19.99,  "yes": true,  "letter": "k",  "text": "Asha",  "list": [    1,    2  ],  "map": {    "a": 1  },  "missing": null,  "pending": "Pending",  "paid": {    "Paid": {      "amount": 5.00    }  }}
types.kav: Kavach code, then what running it prints
  • A Decimal and a BigInt are written as numbers with all their digits: 5.00 stays 5.00.
  • A Char is text of one character; an optional that is none is null.
  • A union case without fields is its name; one with fields is an object holding them, under its name.
  • A Date, Time or DateTime is ISO 8601 text, a DateTime in UTC: see Dates and times.
  • Functions, and maps whose keys aren't String, can't be written: that is a compile error.

A record with a secret field can't be written as JSON, so a secret can't leave in an API response by accident:

use std.json

type Card {
    holder: String
    secret number: String
}

fn main() {
    const c = Card(holder: "asha", number: "4111")
    print(json.stringify(c))
}

The compiler refused the program:

kavach run secret.kav

error: `Card` has the secret field `number`, so it can't be written as JSON (spec 2.11)
secret.kav: Kavach code, then what running it prints