Skip to content

Commit 70bb989

Browse files
authored
doc: update the README for json2 (#16657)
1 parent acbd93b commit 70bb989

File tree

1 file changed

+92
-117
lines changed

1 file changed

+92
-117
lines changed

vlib/x/json2/README.md

Lines changed: 92 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,103 @@
44
`x.json2` is an experimental JSON parser written from scratch on V.
55

66
## Usage
7-
```v oksyntax
7+
#### encode[T]
8+
9+
```v
10+
import x.json2
11+
import time
12+
13+
struct Person {
14+
mut:
15+
name string
16+
age ?int = 20
17+
birthday time.Time
18+
deathday ?time.Time = none
19+
}
20+
21+
fn main() {
22+
mut person := Person{
23+
name: 'Bob'
24+
birthday: time.now()
25+
}
26+
person_json := json2.encode[Person](person)
27+
// person_json == {"name": "Bob", "age": 20, "birthday": "2022-03-11T13:54:25.000Z"}
28+
}
29+
```
30+
31+
#### decode[T]
32+
33+
```v
34+
import x.json2
35+
import time
36+
37+
struct Person {
38+
mut:
39+
name string
40+
age ?int = 20
41+
birthday time.Time
42+
deathday ?time.Time = none
43+
}
44+
45+
fn main() {
46+
resp := '{"name": "Bob", "age": 20, "birthday": ${time.now()}}'
47+
person := json2.decode[Person](resp)!
48+
/*
49+
struct Person {
50+
mut:
51+
name "Bob"
52+
age 20
53+
birthday "2022-03-11 13:54:25"
54+
}
55+
*/
56+
}
57+
```
58+
decode[T] is smart and can auto-convert the types of struct fields - this means
59+
examples below will have the same result
60+
61+
```v ignore
62+
json2.decode[Person]('{"name": "Bob", "age": 20, "birthday": "2022-03-11T13:54:25.000Z"}')!
63+
json2.decode[Person]('{"name": "Bob", "age": 20, "birthday": "2022-03-11 13:54:25.000"}')!
64+
json2.decode[Person]('{"name": "Bob", "age": "20", "birthday": 1647006865}')!
65+
json2.decode[Person]('{"name": "Bob", "age": "20", "birthday": "1647006865"}}')!
66+
```
67+
68+
#### raw decode
69+
70+
```v
871
import x.json2
972
import net.http
1073
1174
fn main() {
12-
// Decoding
13-
resp := http.get('https://example.com')!
75+
resp := http.get('https://reqres.in/api/products/1')!
1476
15-
// raw decode
16-
raw_person := json2.raw_decode(resp.body)!
77+
// This returns an Any type
78+
raw_product := json2.raw_decode(resp.body)!
79+
}
80+
```
81+
#### Casting `Any` type / Navigating
82+
```v
83+
import x.json2
84+
import net.http
1785
18-
// Casting `Any` type / Navigating
19-
person := raw_person.as_map()
20-
name := person['name'].str() // Bob
21-
age := person['age'].int() // 19
22-
pi := person['pi'].f64() // 3.14....
86+
fn main() {
87+
resp := http.get('https://reqres.in/api/products/1')!
88+
89+
raw_product := json2.raw_decode(resp.body)!
90+
91+
product := raw_product.as_map()
92+
data := product['data'] as map[string]json2.Any
2393
24-
// Constructing an `Any` type
94+
id := data['id'].int() // 1
95+
name := data['name'].str() // cerulean
96+
year := data['year'].int() // 2000
97+
}
98+
```
99+
#### Constructing an `Any` type
100+
```v
101+
import x.json2
102+
103+
fn main() {
25104
mut me := map[string]json2.Any{}
26105
me['name'] = 'Bob'
27106
me['age'] = 18
@@ -46,89 +125,11 @@ fn main() {
46125
// "interests":["rock","papers","scissors",null,12],
47126
// "pets":{"Sam":"Maltese"}
48127
//}
49-
50-
// Encode a struct/type to JSON
51-
encoded_json := json2.encode[Person](person2)
52128
}
53129
```
54-
## Using `decode[T]` and `encode[T]`
55-
> Codegen for this feature is still WIP.
56-
> You need to manually define the methods before using the module to structs.
57-
58-
In order to use the `decode[T]` and `encode[T]` function, you need to explicitly define
59-
two methods: `from_json` and `to_json`. `from_json` accepts a `json2.Any` argument
60-
and inside of it you need to map the fields you're going to put into the type.
61-
As for `to_json` method, you just need to map the values into `json2.Any`
62-
and turn it into a string.
63-
64-
```v ignore
65-
struct Person {
66-
mut:
67-
name string
68-
age int = 20
69-
pets []string
70-
}
71-
72-
fn (mut p Person) from_json(f json2.Any) {
73-
obj := f.as_map()
74-
for k, v in obj {
75-
match k {
76-
'name' { p.name = v.str() }
77-
'age' { p.age = v.int() }
78-
'pets' { p.pets = v.arr().map(it.str()) }
79-
else {}
80-
}
81-
}
82-
}
83-
84-
fn (p Person) to_json() string {
85-
mut obj := map[string]json2.Any
86-
obj['name'] = p.name
87-
obj['age'] = p.age
88-
obj['pets'] = p.pets
89-
return obj.str()
90-
}
91-
92-
fn main() {
93-
resp := os.read_file('./person.json')!
94-
person := json2.decode[Person](resp)!
95-
println(person) // Person{name: 'Bob', age: 28, pets: ['Floof']}
96-
person_json := json2.encode[Person](person)
97-
println(person_json) // {"name": "Bob", "age": 28, "pets": ["Floof"]}
98-
}
99-
```
100-
101-
## Using struct tags
102-
`x.json2` can access and use the struct field tags similar to the
103-
`json` module by using the comp-time `$for` for structs.
104-
105-
```v ignore
106-
fn (mut p Person) from_json(f json2.Any) {
107-
mp := an.as_map()
108-
mut js_field_name := ''
109-
$for field in Person.fields {
110-
js_field_name = field.name
111-
112-
for attr in field.attrs {
113-
if attr.starts_with('json:') {
114-
js_field_name = attr.all_after('json:').trim_left(' ')
115-
break
116-
}
117-
}
118-
119-
match field.name {
120-
'name' { p.name = mp[js_field_name].str() }
121-
'age' { u.age = mp[js_field_name].int() }
122-
'pets' { u.pets = mp[js_field_name].arr().map(it.str()) }
123-
else {}
124-
}
125-
}
126-
}
127-
```
128-
129130
### Null Values
130-
`x.json2` has a separate `null` type for differentiating an undefined value and a null value.
131-
To verify that the field you're accessing is a `null`, use `[typ] is json2.Null`.
131+
`x.json2` has a separate `Null` type for differentiating an undefined value and a null value.
132+
To verify that the field you're accessing is a `Null`, use `[typ] is json2.Null`.
132133

133134
```v ignore
134135
fn (mut p Person) from_json(f json2.Any) {
@@ -140,32 +141,6 @@ fn (mut p Person) from_json(f json2.Any) {
140141
}
141142
```
142143

143-
### Custom field names
144-
Aside from using struct tags, you can also just simply cast the base field into a map (`as_map()`)
145-
and access the field you wish to put into the struct/type.
146-
147-
```v ignore
148-
fn (mut p Person) from_json(f json2.Any) {
149-
obj := f.as_map()
150-
p.name = obj['nickname'].str()
151-
}
152-
```
153-
154-
```v oksyntax
155-
import x.json2
156-
157-
fn (p Person) to_json() string {
158-
mut obj := map[string]json2.Any{}
159-
obj['nickname'] = p.name
160-
return obj.str()
161-
}
162-
```
163-
164-
### Undefined Values
165-
Getting undefined values has the same behavior as regular V types.
166-
If you're casting a base field into `map[string]json2.Any` and fetch an undefined entry/value,
167-
it simply returns empty. As for the `[]json2.Any`, it returns an index error.
168-
169144
## Casting a value to an incompatible type
170145
`x.json2` provides methods for turning `Any` types into usable types.
171146
The following list shows the possible outputs when casting a value to an incompatible type.

0 commit comments

Comments
 (0)