Skip to content

x.json2 #

The name json2 was chosen to avoid any unwanted potential conflicts with the > existing codegen tailored for the main json module which is powered by CJSON.

x.json2 is an experimental JSON parser written from scratch on V.

Usage

encode[T]

import x.json2
import time

struct Person {
mut:
    name     string
    age      ?int = 20
    birthday time.Time
    deathday ?time.Time
}

fn main() {
    mut person := Person{
        name:     'Bob'
        birthday: time.now()
    }
    person_json := json2.encode[Person](person)
    // person_json == {"name": "Bob", "age": 20, "birthday": "2022-03-11T13:54:25.000Z"}
}

decode[T]

import x.json2
import time

struct Person {
mut:
    name     string
    age      ?int = 20
    birthday time.Time
    deathday ?time.Time
}

fn main() {
    resp :='{"name": "Bob", "age": 20, "birthday": "${time.now()}"}'
    person := json2.decode[Person](resp)!
    // struct Person {
    //    mut:
    //        name "Bob"
    //        age  20
    //        birthday "2022-03-11 13:54:25"
    //       deathday "2022-03-11 13:54:25"
    // }
}

decode[T] is smart and can auto-convert the types of struct fields - this means examples below will have the same result

json2.decode[Person]('{"name": "Bob", "age": 20, "birthday": "2022-03-11T13:54:25.000Z"}')!
json2.decode[Person]('{"name": "Bob", "age": 20, "birthday": "2022-03-11 13:54:25.000"}')!
json2.decode[Person]('{"name": "Bob", "age": "20", "birthday": 1647006865}')!
json2.decode[Person]('{"name": "Bob", "age": "20", "birthday": "1647006865"}}')!

raw decode

import x.json2
import net.http

fn main() {
    resp := http.get('https://reqres.in/api/products/1')!

    // This returns an Any type
    raw_product := json2.decode[json2.Any](resp.body)!
}

Casting Any type / Navigating

import x.json2
import net.http

fn main() {
    resp := http.get('https://reqres.in/api/products/1')!

    raw_product := json2.decode[json2.Any](resp.body)!

    product := raw_product.as_map()
    data := product['data'] as map[string]json2.Any

    id := data['id'].int() // 1
    name := data['name'].str() // cerulean
    year := data['year'].int() // 2000
}

Constructing an Any type

import x.json2

fn main() {
    mut me := map[string]json2.Any{}
    me['name'] = 'Bob'
    me['age'] = 18

    mut arr := []json2.Any{}
    arr << 'rock'
    arr << 'papers'
    arr << json2.null
    arr << 12

    me['interests'] = arr

    mut pets := map[string]json2.Any{}
    pets['Sam'] = 'Maltese Shitzu'
    me['pets'] = pets

    // Stringify to JSON
    println(me.str())
    //{
    //   "name":"Bob",
    //   "age":18,
    //   "interests":["rock","papers","scissors",null,12],
    //   "pets":{"Sam":"Maltese"}
    //}
}

Null Values

x.json2 has a separate Null type for differentiating an undefined value and a null value. To verify that the field you're accessing is a Null, use [typ] is json2.Null.

fn (mut p Person) from_json(f json2.Any) {
    obj := f.as_map()
    if obj['age'] is json2.Null {
        // use a default value
        p.age = 10
    }
}

Casting a value to an incompatible type

x.json2 provides methods for turning Any types into usable types. The following list shows the possible outputs when casting a value to an incompatible type.

  1. Casting non-array values as array (arr()) will return an array with the value as the content.
  2. Casting non-map values as map (as_map()) will return a map with the value as the content.
  3. Casting non-string values to string (str()) will return theJSON string representation of the value.4. Casting non-numeric values to int/float (int()/i64()/f32()/f64()) will return zero.

Encoding using string builder instead of []u8

To be more performant, json2, in PR 20052, decided to use buffers directly instead of Writers. If you want to use Writers you can follow the steps below:

mut sb := strings.new_builder(64)
mut buffer := []u8{}

json2.encode_value(<some value to be encoded here>, mut buffer)!

sb.write(buffer)!

unsafe { buffer.free() }

Constants #

const null = Null{}

null is an instance of the Null type, to ease comparisons with it.

fn decode #

fn decode[T](val string) !T

decode decodes a JSON string into a specified type.

fn encode #

fn encode[T](val T, config EncoderOptions) string

encode is a generic function that encodes a type into a JSON string.

fn encode_pretty #

deprecated: use `encode(..., prettify: true)` instead
deprecated_after: 2025-10-30
fn encode_pretty[T](typed_data T) string

encode_pretty ...

fn map_from #

fn map_from[T](t T) map[string]Any

map_from converts a struct to a map of Any.

fn raw_decode #

deprecated: use `decode[json2.Any]` instead
deprecated_after: 2025-10-10
fn raw_decode(src string) !Any

Decodes a JSON string into an Any type. Returns an option.

interface BooleanDecoder #

interface BooleanDecoder {
mut:
	// called with converted bool
	// already checked so no error needed
	from_json_boolean(boolean_value bool)
}

implements decoding json true/false

interface Encodable #

interface Encodable {
	json_str() string
}

Encodable is an interface, that allows custom implementations for encoding structs to their string based JSON representations.

interface JsonEncoder #

interface JsonEncoder {
	// to_json returns a string containing an objects json representation
	to_json() string
}

implements encoding json, this is not validated so implementations must be correct

interface NullDecoder #

interface NullDecoder {
mut:
	// only has one value
	// already checked so no error needed
	from_json_null()
}

implements decoding json null

interface NumberDecoder #

interface NumberDecoder {
mut:
	// called with raw string of number e.g. '-1.234e23'
	from_json_number(raw_number string) !
}

implements decoding json numbers, e.g. -1.234e23

interface StringDecoder #

interface StringDecoder {
mut:
	// called with raw string (minus apostrophes) e.g. 'hello, \u2164!'
	from_json_string(raw_string string) !
}

implements decoding json strings, e.g. "hello, \u2164!"

fn (Any) arr #

fn (f Any) arr() []Any

arr uses Any as an array.

fn (Any) as_map #

fn (f Any) as_map() map[string]Any

as_map uses Any as a map.

fn (Any) as_map_of_strings #

fn (f Any) as_map_of_strings() map[string]string

fn (Any) bool #

fn (f Any) bool() bool

bool uses Any as a bool.

fn (Any) f32 #

fn (f Any) f32() f32

f32 uses Any as a 32-bit float.

fn (Any) f64 #

fn (f Any) f64() f64

f64 uses Any as a 64-bit float.

fn (Any) i16 #

fn (f Any) i16() i16

i16 uses Any as a 16-bit integer.

fn (Any) i32 #

fn (f Any) i32() i32

i32 uses Any as a 32-bit integer.

fn (Any) i64 #

fn (f Any) i64() i64

i64 uses Any as a 64-bit integer.

fn (Any) i8 #

fn (f Any) i8() i8

i8 uses Any as a 16-bit integer.

fn (Any) int #

fn (f Any) int() int

int uses Any as an integer.

fn (Any) json_str #

fn (f Any) json_str() string

json_str returns the JSON string representation of the Any type.

fn (Any) prettify_json_str #

deprecated: use `encode(Any(...), prettify: true)` instead
deprecated_after: 2025-10-30
fn (f Any) prettify_json_str() string

prettify_json_str returns the pretty-formatted JSON string representation of the Any type.

fn (Any) str #

fn (f Any) str() string

str returns the string representation of the Any type. Use the json_str method. If you want to use the escaped str() version of the Any type.

fn (Any) to_time #

fn (f Any) to_time() !time.Time

to_time uses Any as a time.Time.

fn (Any) u16 #

fn (f Any) u16() u16

u16 uses Any as a 16-bit unsigned integer.

fn (Any) u32 #

fn (f Any) u32() u32

u32 uses Any as a 32-bit unsigned integer.

fn (Any) u64 #

fn (f Any) u64() u64

u64 uses Any as a 64-bit unsigned integer.

fn (Any) u8 #

fn (f Any) u8() u8

u8 uses Any as a 8-bit unsigned integer.

fn ([]Any) str #

fn (f []Any) str() string

str returns the JSON string representation of the []Any type.

fn (map[string]Any) str #

fn (f map[string]Any) str() string

str returns the JSON string representation of the map[string]Any type.

struct EncoderOptions #

@[params]
struct EncoderOptions {
pub:
	prettify       bool
	indent_string  string = '    '
	newline_string string = '\n'

	enum_as_int bool

	escape_unicode bool
}

EncoderOptions provides a list of options for encoding

struct JsonDecodeError #

struct JsonDecodeError {
	Error
	context string
pub:
	message string

	line      int
	character int
}

struct Null #

struct Null {}

Null is a simple representation of the null value in JSON.

fn (Null) from_json_null #

fn (mut n Null) from_json_null()

from_json_null implements a custom decoder for json2

fn (Null) to_json #

fn (n Null) to_json() string

to_json implements a custom encoder for json2

struct Token #

struct Token {
	lit  []u8      // literal representation of the token
	kind TokenKind // the token number/enum; for quick comparisons
	line int       // the line in the source where the token occurred
	col  int       // the column in the source where the token occurred
}

fn (Token) full_col #

fn (t Token) full_col() int

full_col returns the full column information which includes the length.