summaryrefslogtreecommitdiff
path: root/README.org
blob: 44e98364844772eb2669d475a27b3175b8c9e52d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#+TITLE: JSON meta library

* What is a meta library?
The purpose of this library is to provide a high level abstraction layer for handling JSON.

* Why?
If one wants to write portable Scheme which does some JSON processing, one must either:

- Abandon hope of being portable, and depend on an implementation specific library.
- Use (possibly by writing) a portable JSON library which is redundant, and may conflict with other libraries that expect parsed JSON to be represented in a certain way.
- Write a bunch of cond-expands to act as a portability layer, and use different JSON libraries in different contexts.

This library aims to be an implementation of the latter, which you can just plug in as a dependency, instead of writing your own.

* API
** Values
~json-null~:

This is a constant value which represents null in JSON.
** Constructors
~(json-object pairs ...)~:

Constructs a new JSON object.
~pairs~ must satisfy ~pair?~, with a ~car~ that satisfies ~symbol?~, and a ~cdr~ that satisfies ~json-value?~.
It is an error to construct a ~json-object~ that contains duplicate keys.

An alist can be converted to a JSON object like so: ~(apply json-object alist)~

~(json-list objs ...)~:

Constructs a new JSON list.
~objs~ must satisfy ~json-value?~.

A list can be converted to a JSON list like so: ~(apply json-list some-list)~

*** Syntax
~json~:

Constructs a new JSON value.
The ~json~ macro has ~list~ and ~object~, ~null~, ~true~, and ~false~ keywords, and handles quoting the appropriate terms.

*Example*:

#+begin_src scheme
  (json (object
         (x . 2)
         (y . (list "hello" 1 true null (object (a . (object)))))))
#+end_src

~define-json-record-type~:

Creates a new record-type with an additional procedure definition that will convert a string to an instance of the record.
Objects that were not constructed via a record constructor, but that have at least all of the keys required to construct the record, may be transparently treated as instances of the record-type.

*Example*:

#+begin_src scheme
  (define-json-record-type <point>
    (point x y)
    string->point
    point?
    (x point->x)
    (y point->y set-y!))

  (define a (point 1 2))
  (define b (json (object (x . 3) (y . 4))))
  (define c (string-point "{\"x\": 5, \"y\": 6}"))

  (and (point? a) (point? b) (point? c)) ; => #t
  (eq? 3 (point->x b)) ; => #t
  (set-y! a 5)
  (set-y! b 5)
  (eq? (point->y a) (point->y b)) ; => #t
#+end_src
** Predicates
~(json-value? obj)~:

Returns true if ~obj~ is a value that can be serialized as JSON.
This is true for values returned by the [[Constructors][constructors]], ~json-null~, numbers, strings, and booleans.

~(json-object? obj)~:

Returns true if ~obj~ is a value that can be serialized as a JSON object.
Either the result of deserializing a string formatted as a JSON object, the ~json-object~ constructor, or a constructor created as the result of a ~define-json-record-type~ expression.

~(json-list? obj)~:

Returns true if ~obj~ is a value that can be serialized as a JSON list.
Either the result of deserializing a string formatted as a JSON list, or from the ~json-list~ constructor.

~(json-null? obj)~:

Returns true if ~obj~ is ~json-null~.

~(json-object-contains-key? obj key)~:

Returns true if ~obj~ contains the ~key~.
** Serialization
~(json->string obj)~:

Convert a ~json-value?~ to a JSON formatted ~string?~.

~(string->json str)~

Converts a ~string?~ into a ~json-value?~
** Selectors
~(json-object-ref obj key)~:

Returns the ~json-value?~ associated with ~key~ in ~obj~.
~key~ should be a ~symbol?~.

The behavior when ~key~ is not found in ~obj~ can be controlled with the ~json-key-not-found~ parameter.
The value of ~json-key-not-found~ should be a procedure of no arguments, and the return value of the procedure is returned, if any exists.
The default behavior of ~json-key-not-found~ will return nothing to its continuation.

~(json-list-ref lst i)~:

Returns the ~json-value?~ at index ~i~ of ~lst~.

~(json-list-length lst)~:

Returns the length of ~lst~.

~(json-ref json ref refs ...)~:

General JSON reference accessor.

If ~json~ is a ~json-list?~ and ~ref~ is a ~number?~, get the element at that index of the list.

If ~json~ is a ~json-object?~ and ~ref~ is a ~symbol?~, get the value associated with that key in the object.

If there are more ~refs ...~, they are recursively applied.
** Conversion
~(json-object->alist obj)~:

Convert ~obj~ to a ~list?~ of ~pair?~ where the ~car~ of each pair is a ~symbol?~ and the ~cdr~ is the associated ~json-value?~.

~(json-list->list lst)~:

Convert ~lst~ to a ~list?~ of ~json-value?~.

** Examples
#+begin_src scheme
  (json-list->list (apply json-list lst))	; => lst
#+end_src

#+begin_src scheme
  (json-object->alist (apply json-object alist)) ; => alist
#+end_src

#+begin_src scheme
  (json-null? (string->json "null"))	; => #t
#+end_src

#+begin_src scheme
   (json-object-contains-key?
    (json-object '(a . 5)
                 `(b . ,(json-list 1 2 3)))
    'a)					; => #t

  (json-object-contains-key?
   (json-object '(a . 5)
                `(b . ,(json-list 1 2 3)))
   'c)					; => #f
#+end_src

#+begin_src scheme
  (json-ref
   (json-object `(x . ,(json-list "hello" "world")))
   'x
   0) ; => "hello"
#+end_src

#+begin_src scheme
  (import (srfi 210))

  (case-receive (json-ref (json-object `("x" . ,(json-list "hello" "world"))) "x")
    (() 'not-found)
    ((x) (json-list? x)))			; => #t

  (case-receive (json-ref (json-object `("x" . ,(json-list "hello" "world"))) "y")
    (() 'not-found)
    ((x) (json-list? x)))			; => not-found
#+end_src

* Feedback
Please email me at: contact (at) robbyzambito (dot) me if you have any suggestions or would like for me to add support for another JSON library.