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
871import x.json2
972import net.http
1073
1174fn 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
134135fn (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.
171146The following list shows the possible outputs when casting a value to an incompatible type.
0 commit comments