|
1
|
# JSON API: General Conventions |
|
2
|
([⬑JSON API Index](index.md)) |
|
3
|
|
|
4
|
Jump to: |
|
5
|
|
|
6
|
* [JSON Property Naming](#property-names) |
|
7
|
* [HTTP GET Requests](#http-get) |
|
8
|
* [HTTP POST Requests](#http-post) |
|
9
|
* [POST Request Envelope](#request-envelope) |
|
10
|
* [Request Parameter Data Types](#request-param-types) |
|
11
|
* [Response Envelope](#response-envelope) |
|
12
|
* [HTTP Response Headers](#http-response-header) |
|
13
|
* [CLI vs. HTTP Mode](#cli-vs-http) |
|
14
|
* [Simulating POSTed data](#simulating-post-data) |
|
15
|
* [Indentation/Formatting of JSON Output](#json-indentation) |
|
16
|
* [JSONP](#jsonp) |
|
17
|
* [API Result Codes](#result-codes) |
|
18
|
|
|
19
|
--- |
|
20
|
|
|
21
|
<a id="property-names"></a> |
|
22
|
# JSON Property Naming |
|
23
|
|
|
24
|
Since most JSON usage conventionally happens in JavaScript |
|
25
|
environments, this API has (without an explicit decision ever having |
|
26
|
been made) adopted the ubiquitous JavaScript convention of |
|
27
|
`camelCaseWithStartingLower` for naming properties in JSON objects. |
|
28
|
|
|
29
|
<a id="http-get"></a> |
|
30
|
# HTTP GET Requests |
|
31
|
|
|
32
|
Many (if not most) requests can be made via simple GET requests, e.g. we |
|
33
|
*could* use any of the following patterns for a hypothetical JSON-format |
|
34
|
timeline: |
|
35
|
|
|
36
|
- `https://..../timeline/json` |
|
37
|
- `/timeline?format=json` |
|
38
|
- `/timeline?json=1` |
|
39
|
- `/timeline.json` |
|
40
|
- `/json/timeline?...options...` |
|
41
|
|
|
42
|
The API settled on the `/json/...` convention, primarily because it |
|
43
|
simplifies dispatching and argument-handling logic compared to the |
|
44
|
`/[.../]foo.json` approach. Using `/json/...` allows us to unify that |
|
45
|
logic for all JSON sub-commands, for both CLI and HTTP modes. |
|
46
|
|
|
47
|
<a id="http-post"></a> |
|
48
|
# HTTP Post Requests |
|
49
|
|
|
50
|
Certain requests, mainly things like editing checkin messages and |
|
51
|
committing new files entirely, require POST data. This is fundamentally |
|
52
|
very simple to do - clients post plain/unencoded JSON using a common |
|
53
|
wrapper envelope which contains the request-specific data to submit as |
|
54
|
well as some request-independent information (like authentication data). |
|
55
|
|
|
56
|
<a id="request-envelope"></a> |
|
57
|
## POST Request Envelope |
|
58
|
|
|
59
|
POST requests are sent to the same URL as their GET counterpart (if any, |
|
60
|
else their own path), and are sent as plain-text/unencoded JSON wrapped |
|
61
|
in a common request envelope with the following properties: |
|
62
|
|
|
63
|
- `requestId`: Optional arbitrary JSON value, not used by fossil, but |
|
64
|
returned as-is in responses. |
|
65
|
- `command`: Provides a secondary mechanism for specifying which JSON |
|
66
|
command should be run. A request path of /json/foo/bar is equivalent |
|
67
|
to a request with path=/json and command=foo/bar. Note that subpaths |
|
68
|
do not work this way. e.g. path=/json/foo, command=bar will not |
|
69
|
work, but path=/json, command=foo/bar will. This option is |
|
70
|
particularly useful when generating JSON for piping in to CLI mode, |
|
71
|
but it also has some response-dispatching uses on the client side. |
|
72
|
- `authToken`: Authentication token. Created by a login |
|
73
|
request. Determines what access rights the user has, and any given |
|
74
|
request may require specific rights. In principle this is required |
|
75
|
by any request which needs non-guest privileges, but cookie-aware |
|
76
|
clients do not manually need to track this (it is managed as a |
|
77
|
cookie by the agent/browser). |
|
78
|
- Note that when accessing fossil over a local server instance |
|
79
|
which was started with the `--localauth` flag, the `authToken` |
|
80
|
will be ignored and need not be sent with any requests. The user |
|
81
|
will automatically be given full privileges, as if they were |
|
82
|
using CLI mode. |
|
83
|
- `payload`: Command-specific parameters. Most can optionally come in |
|
84
|
via GET parameters, but those taking complex structures expect them |
|
85
|
to be placed here. |
|
86
|
- `indent`: Optionally specifies indentation for the output. 0=no |
|
87
|
indention. 1=a single TAB character for each level of |
|
88
|
indentation. >1 means that many spaces per level. e.g. indent=7 |
|
89
|
means to indent 7 spaces per object/array depth level. cson also |
|
90
|
supports other flags for fine-tuning the output spacing, and adding |
|
91
|
them to this interface might be interesting at some |
|
92
|
point. e.g. whether or not to add a newline to the output. CLI mode |
|
93
|
adds extra indentation by default, whereas CGI/server modes produce |
|
94
|
unindented output by default. |
|
95
|
- `jsonp`: Optional String (client function name). Requests which |
|
96
|
include this will be returned with `Content-Type |
|
97
|
application/javascript` and will be wrapped up in a function call |
|
98
|
using the given name. e.g. if `jsonp=foo` then the result would look like:\ |
|
99
|
`foo( {...the response envelope...} )` |
|
100
|
|
|
101
|
The API allows most of those (normally all but the payload) to come in |
|
102
|
as either GET parameters or properties of the top-level POSTed request |
|
103
|
JSON envelope, with GET taking priority over POST. (Reminder to self: we |
|
104
|
could potentially also use values from cookies. Fossil currently only |
|
105
|
uses 1 cookie (the login token), and I'd prefer to keep it that way.) |
|
106
|
|
|
107
|
POST requests without such an envelope will be rejected, generating a |
|
108
|
Fossil/JSON error response (as opposed to an HTTP error response). GET |
|
109
|
requests, by definition, never have an envelope. |
|
110
|
|
|
111
|
POSTed client requests *must* send a Content-Type header of either |
|
112
|
`application/json` , `application/javascript`, or `text/plain`, or the |
|
113
|
JSON-handling code will never see the POST data. The POST handler |
|
114
|
optimistically assumes that type `text/plain` "might be JSON", since |
|
115
|
`application/json` is a newer convention which many existing clients |
|
116
|
do not use (as of the time these docs were written, back in 2011). |
|
117
|
|
|
118
|
## POST Envelope vs. `POST.payload` |
|
119
|
|
|
120
|
|
|
121
|
When this document refers to POST data, it is referring to top-level |
|
122
|
object in JSON-format POSTed input data. When we say `POST.payload` we |
|
123
|
refer to the "payload" property of the POST data. While fossil's core |
|
124
|
handles *form-urlencoded* POST data, if such data is sent in then |
|
125
|
parsing it as JSON cannot succeed, which means that (at worst) the |
|
126
|
JSON-mode bits will "not see" any POST data. Data POSTed to the JSON API |
|
127
|
must be sent non-form-urlencoded (i.e. as plain text). |
|
128
|
|
|
129
|
Framework-level configuration options are always set via the top-level |
|
130
|
POST envelope object or GET parameters. Request-specific options are set |
|
131
|
either in `POST.payload` or GET parameters (though the former is required |
|
132
|
in some cases). Here is an example which demonstrates the possibly |
|
133
|
not-so-obvious difference between the two types of options (framework |
|
134
|
vs. request-specific): |
|
135
|
|
|
136
|
```json |
|
137
|
{ |
|
138
|
"requestId":"my request", // standard envelope property (optional) |
|
139
|
"command": "timeline/wiki", // also standard |
|
140
|
"indent":2, // output indention is a framework-level option |
|
141
|
"payload":{ // *anything* in the payload is request-specific |
|
142
|
"limit":1 |
|
143
|
} |
|
144
|
} |
|
145
|
``` |
|
146
|
|
|
147
|
When a given parameter is set in two places, e.g. GET and POST, or |
|
148
|
POST-from-a-file and CLI parameters, which one takes precedence |
|
149
|
depends on the concrete command handler (and may be unspecified). Most |
|
150
|
will give precedence to CLI and GET parameters, but POSTed values are |
|
151
|
technically preferred for non-string data because no additional "type |
|
152
|
guessing" or string-to-whatever conversion has to be made (GET/CLI |
|
153
|
parameters are *always* strings, even if they look like a number or |
|
154
|
boolean). |
|
155
|
|
|
156
|
|
|
157
|
<a id="request-param-types"></a> |
|
158
|
# Request Parameter Data Types |
|
159
|
|
|
160
|
When parameters are sent in the form of GET or CLI arguments, they are |
|
161
|
inherently strings. When they come in from JSON they keep their full |
|
162
|
type (boolean, number, etc.). All parameters in this API specify what |
|
163
|
*type* (or types) they must (or may) be. For strings, there is no |
|
164
|
internal conversion/interpretation needed for GET- or CLI-provided |
|
165
|
parameters, but for other types we sometimes have to convert strings to |
|
166
|
other atomic types. This section describes how those string-to-whatever |
|
167
|
conversions behave. |
|
168
|
|
|
169
|
No higher-level constructs, e.g. JSON **arrays** or **objects**, are |
|
170
|
accepted in string form. Such parameters must be set in the POST |
|
171
|
envelope or payload, as specified by the specific API. |
|
172
|
|
|
173
|
This API does not currently use any **floating-point** parameters, but |
|
174
|
does return floating-point results in a couple of places. |
|
175
|
|
|
176
|
For **integer** parameters we use a conventional string-to-int algorithm |
|
177
|
and assume base 10 (analog to atoi(3)). The API may err on the side of |
|
178
|
usability when given technically invalid values. e.g. "123abc" will |
|
179
|
likely be interpreted as the integer 123. No APIs currently rely on |
|
180
|
integer parameters with more than 32 bits (signedness is call-dependent |
|
181
|
but few, if any, use negative values). |
|
182
|
|
|
183
|
**Boolean** parameters are a bit schizophrenic... |
|
184
|
|
|
185
|
In **CLI mode**, boolean flags do not have a value, per se, and thus |
|
186
|
require no string-to-bool conversion. e.g. |
|
187
|
`fossil foo -aBoolOpt -non-bool-opt value`. |
|
188
|
|
|
189
|
Those which arrive as strings via **GET parameters** treat any of the |
|
190
|
following as true: a string starting with a character in the set |
|
191
|
`[1-9tT]`. All other string values are considered to be false for this |
|
192
|
purpose. |
|
193
|
|
|
194
|
Those which are part of the **POST data** are normally (but not always - |
|
195
|
it depends on the exact context) evaluated as the equivalent of |
|
196
|
JavaScript booleans. e.g. if we have `POST.envelope.foo="f"`, and evaluate |
|
197
|
it as a JSON boolean (as opposed to a string-to-bool conversion), the |
|
198
|
result will be true because the underlying JSON API follows JavaScript |
|
199
|
semantics for any-type-to-bool conversions. As long as clients always |
|
200
|
send "proper" booleans in their POST data, the difference between |
|
201
|
GET/CLI-provided booleans should never concern them. |
|
202
|
|
|
203
|
TODO: consider changing the GET-value-to-bool semantics to match the JS |
|
204
|
semantics, for consistency (within the JSON API at least, but that might |
|
205
|
cause inconsistencies vis-a-vis the HTML interface). |
|
206
|
|
|
207
|
<a id="response-envelope"></a> |
|
208
|
# Response Envelope |
|
209
|
|
|
210
|
Every response comes in the form of an HTTP response or (in CLI mode) |
|
211
|
JSON sent to stdout. The body of the response is a JSON object following |
|
212
|
a common envelope format. The envelope has the following properties: |
|
213
|
|
|
214
|
|
|
215
|
- `fossil`: Fossil server version string. This property is basically |
|
216
|
"the official response envelope marker" - if it is set, clients can |
|
217
|
"probably safely assume" that the object indeed came from one of the |
|
218
|
Fossil/JSON APIs. This API never creates responses which do not |
|
219
|
contain this property. |
|
220
|
- `requestId`: Only set if the request contained it, and then it is |
|
221
|
echoed back to the caller as-is. This can be used to determine |
|
222
|
(client-side) which request a given response is coming in for |
|
223
|
(assuming multiple asynchronous requests are pending). In practice |
|
224
|
this generally isn’t needed because response handling tends to be |
|
225
|
done by closures associated with the original request object (at |
|
226
|
least in JavaScript code). In languages without closures it might |
|
227
|
have some use. It may be any legal JSON value - it need not be |
|
228
|
confined to a string or number. |
|
229
|
- `resultCode`: Standardized result code string in the form |
|
230
|
`FOSSIL-####`. Only error responses contain a `resultCode`. |
|
231
|
- `resultText`: Possibly a descriptive string, possibly |
|
232
|
empty. Supplements the resultCode, but can also be set on success |
|
233
|
responses (but normally isn't). Clients must not rely on any |
|
234
|
specific values being set here. |
|
235
|
- `payload`: Request-specific response payload (data type/structure is |
|
236
|
request-specific). The payload is never set for error responses, |
|
237
|
only for success responses (and only those which actually have a |
|
238
|
payload - not all do). |
|
239
|
- `timestamp`: Response timestamp (GMT Unix Epoch). We use seconds |
|
240
|
precision because I did not know at the time that Fossil actually |
|
241
|
records millisecond precision. |
|
242
|
- `payloadVersion`: Not initially needed, but reserved for future use |
|
243
|
in maintaining version compatibility when the format of a given |
|
244
|
response type's payload changes. If needed, the "first version" |
|
245
|
value is assumed to be 0, for semantic [near-]compatibility with the |
|
246
|
undefined value clients see when this property is not set. |
|
247
|
- `command`: Normalized form of the command being run. It consists of |
|
248
|
the "command" (non-argument) parts of the request path (or CLI |
|
249
|
positional arguments), excluding the initial "/json/" part. e.g. the |
|
250
|
"command" part of "/json/timeline/checkin?a=b" (CLI: json timeline |
|
251
|
checkin...) is "timeline/checkin" (both in CLI and HTTP modes). |
|
252
|
- `apiVersion`: Not yet used, but reserved for a numeric value which |
|
253
|
represents the JSON API's version (which can be used to determine if |
|
254
|
it has a given feature or not). This will not be implemented until |
|
255
|
it's needed. |
|
256
|
- `warnings`: Reserved for future use as a standard place to put |
|
257
|
non-fatal warnings in responses. Will be an array but the warning |
|
258
|
structure/type is not yet specified. Intended primarily as a |
|
259
|
debugging tool, and will "probably not" become part of the public |
|
260
|
client interface. |
|
261
|
- `g`: Fossil administrators (those with the "a" or "s" permissions) |
|
262
|
may set the `debugFossilG` boolean request parameter (CLI: |
|
263
|
`--json-debug-g`) to enable this property for any given response. It |
|
264
|
contains a good deal of the server-side internal state at the time |
|
265
|
the response was generated, which is often useful in debuggering |
|
266
|
problems. Trivia: it is called "g" because that's the name of |
|
267
|
fossil's internal global state object. |
|
268
|
- `procTimeMs`: For debugging only - generic clients must not rely on |
|
269
|
this property. Contains the number of milliseconds the JSON command |
|
270
|
processor needed to dispatch and process the command. TODO: move the |
|
271
|
timer into the fossil core so that we can generically time its |
|
272
|
responses and include the startup overhead in the time calculation. |
|
273
|
|
|
274
|
|
|
275
|
|
|
276
|
<a id="http-response-header"></a> |
|
277
|
# HTTP Response Headers |
|
278
|
|
|
279
|
The Content-Type HTTP header of a response will be either |
|
280
|
application/json, application/javascript, or text/plain, depending on |
|
281
|
whether or not we are in JSONP mode or (failing that) the contents of |
|
282
|
the "Accept" header sent in the request. The response type will be |
|
283
|
text/plain if it cannot figure out what to do. The response's |
|
284
|
Content-Type header *may* contain additional metadata, e.g. it might |
|
285
|
look like: application/json; charset=utf-8 |
|
286
|
|
|
287
|
Apropos UTF-8: note that JSON is, by definition, Unicode and recommends |
|
288
|
UTF-8 encoding (which is what we use). That means if your console cannot |
|
289
|
handle UTF-8 then using this API in CLI mode might (depending on the |
|
290
|
content) render garbage on your screen. |
|
291
|
|
|
292
|
|
|
293
|
<a id="cli-vs-http"></a> |
|
294
|
# CLI vs. HTTP Mode |
|
295
|
|
|
296
|
CLI (command-line interface) and HTTP modes (CGI and standalone server) |
|
297
|
are consolidated in the same implementations and behave essentially |
|
298
|
identically, with only minor exceptions. |
|
299
|
|
|
300
|
An HTTP path of `/json/foo` translates to the CLI command `fossil json |
|
301
|
foo`. CLI mode takes options in the fossil-convention forms (e.g. `--foo 3` |
|
302
|
or `-f 3`) whereas HTTP mode takes them via GET/POST data (e.g. `?foo=1`). |
|
303
|
(Note that per long-standing fossil convention CLI parameters taking a |
|
304
|
value do not use an equal sign before the value!) |
|
305
|
|
|
306
|
For example: |
|
307
|
|
|
308
|
- HTTP: `/json/timeline/wiki?after=2011-09-01&limit=3` |
|
309
|
- CLI: `fossil json timeline wiki --after 2011-09-01 --limit 3` |
|
310
|
|
|
311
|
Some commands may only work in one mode or the other (for various |
|
312
|
reasons). In CLI mode the user automatically has full setup/admin |
|
313
|
access. |
|
314
|
|
|
315
|
In HTTP mode, request-specific options can also be specified in the |
|
316
|
`POST.payload` data, and doing so actually has an advantage over |
|
317
|
specifying them as URL parameters: posting JSON data retains the full |
|
318
|
type information of the values, whereas GET-style parameters are always |
|
319
|
strings and must be explicitly type-checked/converted (which may produce |
|
320
|
unpredictable results when given invalid input). That said, oftentimes |
|
321
|
it is more convenient to pass the options via URL parameters, rather |
|
322
|
than generate the request envelope and payload required by POST |
|
323
|
requests, and the JSON API makes some extra effort to treat GET-style |
|
324
|
parameters type-equivalent to their POST counterparts. If a property |
|
325
|
appears in both GET and `POST.payload`, GET-style parameters *typically* |
|
326
|
take precedence over `POST.payload` by long-standing convention (=="PHP |
|
327
|
does it this way by default"). |
|
328
|
|
|
329
|
(That is, however, subject to eventual reversal because of the |
|
330
|
stronger type safety provided by POSTed JSON. Philosophically |
|
331
|
speaking, though, GET *should* take precedence, in the same way that |
|
332
|
CLI-provided options conventionally override app-configuration-level |
|
333
|
options.) |
|
334
|
|
|
335
|
One notable functional difference between CLI and HTTP modes is that in |
|
336
|
CLI mode error responses *might* be accompanied by a non-0 exit status |
|
337
|
(they "should" always be, but there might be cases where that does not |
|
338
|
yet happen) whereas in HTTP mode we always try to exit with code 0 to |
|
339
|
avoid generating an HTTP 500 ("internal server error"), which could keep |
|
340
|
the JSON response from being delivered. The JSON code only intentionally |
|
341
|
allows an HTTP 500 when there is a serious internal error like |
|
342
|
allocation or assertion failure. HTTP clients are expected to catch |
|
343
|
errors by evaluating the response object, not the HTTP result code. |
|
344
|
|
|
345
|
<a id="simulating-post-data"></a> |
|
346
|
# Simulating POSTed data |
|
347
|
|
|
348
|
We have a mechanism to feed request data to CLI mode via |
|
349
|
files (simulating POSTed data), as demonstrated in this example: |
|
350
|
|
|
351
|
```console |
|
352
|
$ cat in.json |
|
353
|
{ "command": "timeline/wiki", "indent":2, "payload":{"limit":1}} |
|
354
|
$ fossil json --json-input in.json # use filename - for stdin |
|
355
|
``` |
|
356
|
|
|
357
|
The above is equivalent to: |
|
358
|
|
|
359
|
```console |
|
360
|
$ echo '{"indent":2, "payload":{"limit":1}}' \ |
|
361
|
| fossil json timeline wiki --json-input - |
|
362
|
``` |
|
363
|
|
|
364
|
Note that the "command" JSON parameter is only checked when no json |
|
365
|
subcommand is provided on the CLI or via the HTTP request path. Thus we |
|
366
|
cannot pass the CLI args "json timeline" in conjunction with a "command" |
|
367
|
string of "wiki" this way. |
|
368
|
|
|
369
|
***HOWEVER...*** |
|
370
|
|
|
371
|
Much of the existing JSON code was written before the `--json-input` |
|
372
|
option was possible. Because of this, there might be some |
|
373
|
"misinteractions" when providing request-specific options via *both* |
|
374
|
CLI options and simulated POST data. Those cases will eventually be |
|
375
|
ironed out (with CLI options taking precedence). Until then, when |
|
376
|
"POSTing" data in CLI mode, for consistent/predictible results always |
|
377
|
provide any options via the JSON request data, not CLI arguments. That |
|
378
|
said, there "should not" be any blatant incompatibilities, but some |
|
379
|
routines will prefer `POST.payload` over CLI/GET arguments, so there |
|
380
|
are some minor inconsistencies across various commands with regards to |
|
381
|
which source (POST/GET/CLI) takes precedence for a given option. The |
|
382
|
precedence "should always be the same," but currently cannot be due to |
|
383
|
core fossil implementation details (the internal consolidation of |
|
384
|
GET/CLI/POST vars into a single set). |
|
385
|
|
|
386
|
|
|
387
|
<a id="json-indentation"></a> |
|
388
|
# Indentation/Formatting of JSON Output |
|
389
|
|
|
390
|
CLI mode accepts the `--indent|-I #` option to set the indention level |
|
391
|
and HTTP mode accepts `indent=#` as a GET/POST parameter. The semantics |
|
392
|
of the indention level are derived from the underlying JSON library and |
|
393
|
have the following meanings: 0 (zero) or less disables all superfluous |
|
394
|
indentation (this is the default in HTTP mode). A value of 1 uses 1 hard |
|
395
|
TAB character (ASCII 0x09) per level of indention (the default in CLI |
|
396
|
mode). Values greater than 1 use that many whitespaces (ASCII 32d) per |
|
397
|
level of indention. e.g. a value of 7 uses 7 spaces per level of |
|
398
|
indention. There is no way to specify one whitespace per level, but if |
|
399
|
you *really* want one whitespace instead of one tab (same data size) you |
|
400
|
can filter the output to globally replace ASCII 9dec (TAB) with ASCII |
|
401
|
32dec (space). Because JSON string values *never* contain hard tabs |
|
402
|
(they are represented by `\t`) there is no chance that such a global |
|
403
|
replacement will corrupt JSON string contents - only the formatting will |
|
404
|
be affected. |
|
405
|
|
|
406
|
Potential TODO: because extraneous indention "could potentially" be used |
|
407
|
as a form of DoS, the option *might* be subject to later removal from HTTP |
|
408
|
mode (in CLI it's fine). |
|
409
|
|
|
410
|
In HTTP mode no trailing newline is added to the output, whereas in CLI |
|
411
|
mode one is normally appended (exception: in JSONP mode no newline is |
|
412
|
appended, to (rather pedantically and arbitraily) allow the client to |
|
413
|
add a semicolon at the end if he likes). There is currently no option to |
|
414
|
control the newline behaviour, but the underlying JSON code supports |
|
415
|
this option, so adding it to this API is just a matter of adding the |
|
416
|
CLI/HTTP args for it. |
|
417
|
|
|
418
|
Pedantic note: internally the indention level is stored as a single |
|
419
|
byte, so giving large indention values will cause harmless numeric |
|
420
|
overflow (with only cosmetic effects), meaning, e.g., 257 will overflow |
|
421
|
to the value 1. |
|
422
|
|
|
423
|
Potential TODO: consider changing cson's indention mechanism to use a |
|
424
|
*signed* number, using negative values for tabs and positive for |
|
425
|
whitespace count (or the other way around). This would require more |
|
426
|
doc changes than code changes :/. |
|
427
|
|
|
428
|
|
|
429
|
<a id="jsonp"></a> |
|
430
|
# JSONP |
|
431
|
|
|
432
|
The API supports JSONP-style output. The caller specifies the callback |
|
433
|
name and the JSON response will be wrapped in a function call to that |
|
434
|
name. For HTTP mode pass the `jsonp=string` option (via GET or POST |
|
435
|
envelope) and for CLI use `--jsonp string`. |
|
436
|
|
|
437
|
For example, if we pass the JSONP name `myCallback` then a response will |
|
438
|
look like: |
|
439
|
|
|
440
|
```js |
|
441
|
myCallback({...response...}) |
|
442
|
``` |
|
443
|
|
|
444
|
Note that fossil does not evaluate the callback name itself, other than |
|
445
|
to verify that it is-a string, so "garbage in, garbage out," and all |
|
446
|
that. (Remember that CLI and GET parameters are *always* strings, even |
|
447
|
if they *look* like numbers.) |
|
448
|
|
|
449
|
|
|
450
|
<a id="result-codes"></a> |
|
451
|
# API Result Codes |
|
452
|
|
|
453
|
Result codes are strings which tell the client whether or not a given |
|
454
|
API call succeeded or failed, and if it failed *perhaps* some hint as to |
|
455
|
why it failed. |
|
456
|
|
|
457
|
The result code is available via the resultCode property of every |
|
458
|
*error* response envelope. Since having a result code value for success |
|
459
|
responses is somewhat redundant, success responses contain no resultCode |
|
460
|
property. In practice this simplifies error checking on the client side. |
|
461
|
|
|
462
|
The codes are strings in the form `FOSSIL-####`, where `####` is a |
|
463
|
4-digit integral number, left-padded with zeros. The numbers follow |
|
464
|
these conventions: |
|
465
|
|
|
466
|
- The number 0000 is reserved for the "not an error" (OK) case. Since |
|
467
|
success responses do not contain a result code, clients won't see |
|
468
|
this value (except in documentation). |
|
469
|
- All numbers with a leading 0 are reserved for *potential* future use |
|
470
|
in reporting non-fatal warnings. |
|
471
|
- Despite *possibly* having leading zeros, the numbers are decimal, |
|
472
|
not octal. Script code which uses eval() or similar to produce |
|
473
|
integers from them may need to take that into account. |
|
474
|
- The 1000ths and 100ths places of the number describe the general |
|
475
|
category of the error, e.g. authentication- vs. database- vs. usage |
|
476
|
errors. The 100ths place is more specific than the 1000ths place, |
|
477
|
allowing two levels of sub-categorization (which "should be enough" |
|
478
|
for this purpose). This separation allows the server administrator |
|
479
|
to configure the level of granularity of error reporting. e.g. some |
|
480
|
admins consider error messages to be security-relevant and like to |
|
481
|
"dumb them down" on their way to the client, whereas developers |
|
482
|
normally want to see very specific error codes when tracking down a |
|
483
|
problem. We can offer a configuration option to "dumb down" error |
|
484
|
codes to their generic category by simply doing a modulo 100 |
|
485
|
(or 1000) against the native error code number. e.g. FOSSIL-1271 |
|
486
|
could (via a simple modulo) be reduced to FOSSIL-1200 or |
|
487
|
FOSSIL-1000, depending on the paranoia level of the sysadmin. I have |
|
488
|
tried to order the result code numbers so that a dumb-down level of |
|
489
|
2 provides reasonably usable results without giving away too much |
|
490
|
detail to malicious clients.\ |
|
491
|
(**TODO:** `g.json.errorDetailParanoia` is used to set the |
|
492
|
default dumb-down level, but it is currently set at compile-time. |
|
493
|
It needs to be moved to a config option. We have a chicken/egg scenario |
|
494
|
with error reporting and db access there (where the config is |
|
495
|
stored).) |
|
496
|
- Once a number is assigned to a given error condition (and actually |
|
497
|
used somewhere), it may not be changed/redefined. JSON clients need |
|
498
|
to be able to rely on stable result codes in order to provide |
|
499
|
adequate error reporting to their clients, and possibly for some |
|
500
|
error recovery logic as well (i.e. to decide whether to abort or |
|
501
|
retry). |
|
502
|
|
|
503
|
The *tentative* list of result codes is shown in the following table. |
|
504
|
These numbers/ranges are "nearly arbitrarily" chosen except for the |
|
505
|
"special" value 0000. |
|
506
|
|
|
507
|
**Maintenance reminder:** these codes are defined in |
|
508
|
[`src/json_detail.h`](/finfo/src/json_detail.h) (enum |
|
509
|
`FossilJsonCodes`) and assigned default `resultText` values in |
|
510
|
[`src/json.c:json_err_cstr()`](/finfo/src/json.c). Changes there need |
|
511
|
to be reflected here (and vice versa). Also, we have assertions in |
|
512
|
place to ensure that C-side codes are in the range 1000-9999, so do |
|
513
|
not just go blindly change the numeric ranges used by the enum. |
|
514
|
|
|
515
|
|
|
516
|
**`FOSSIL-0###`: Non-error Category** |
|
517
|
|
|
518
|
- `FOSSIL-0000`: Success/not an error. Succesful responses do not |
|
519
|
contain a resultCode, so clients should never see this. |
|
520
|
- `FOSSIL-0###`: Reserved for potential future use in reporting |
|
521
|
non-fatal warnings. |
|
522
|
|
|
523
|
|
|
524
|
|
|
525
|
**`FOSSIL-1000`: Generic Errors Category** |
|
526
|
|
|
527
|
- `FOSSIL-1101`: Invalid request. Request envelope is invalid or |
|
528
|
missing. |
|
529
|
- `FOSSIL-1102`: Unknown JSON command. |
|
530
|
- `FOSSIL-1103`: Unknown/unspecified error |
|
531
|
- `FOSSIL-1104`: RE-USE |
|
532
|
- `FOSSIL-1105`: A server-side timeout was reached. (i’m not sure we |
|
533
|
can actually implement this one, though.) |
|
534
|
- `FOSSIL-1106`: Assertion failed (or would have had we |
|
535
|
continued). Note: if an `assert()` fails in CGI/server modes, the HTTP |
|
536
|
response will be code 500 (Internal Server Error). We want to avoid |
|
537
|
that and return a JSON response instead. All of that said - there seems |
|
538
|
to be little reason to implement this, since assertions are "truly |
|
539
|
serious" errors. |
|
540
|
- `FOSSIL-1107`: Allocation/out of memory error. This cannot be reasonably |
|
541
|
reported because fossil aborts if an allocation fails. |
|
542
|
- `FOSSIL-1108`: Requested API is not yet implemented. |
|
543
|
- `FOSSIL-1109`: Panic! Fossil's `fossil_panic()` or `cgi_panic()` was |
|
544
|
called. In non-JSON HTML mode this produces an HTTP 500 |
|
545
|
error. Clients "should" report this as a potential bug, as it |
|
546
|
"possibly" indicates that the C code has incorrect argument- or |
|
547
|
error handling somewhere. |
|
548
|
- `FOSSIL-1110`: Reading of artifact manifest failed. Time to contact |
|
549
|
your local fossil guru. |
|
550
|
- `FOSSIL-1111`: Opening of file failed (e.g. POST data provided to |
|
551
|
CLI mode). |
|
552
|
|
|
553
|
|
|
554
|
**`FOSSIL-2000`: Authentication/Access Error Category** |
|
555
|
|
|
556
|
- `FOSSIL-2001`: Privileged request was missing authentication |
|
557
|
token/cookie. |
|
558
|
- `FOSSIL-2002`: Access to requested resource was denied. Oftentimes |
|
559
|
the `resultText` property will contain a human-language description of |
|
560
|
the access rights needed for the given command. |
|
561
|
- `FOSSIL-2003`: Requested command is not available in the current |
|
562
|
operating mode. Returned in CLI mode by commands which require HTTP |
|
563
|
mode (e.g. login), and vice versa. FIXME: now that we can simulate |
|
564
|
POST in CLI mode, we can get rid of this distinction for some of the |
|
565
|
commands. |
|
566
|
- `FOSSIL-2100`: Login Failed. |
|
567
|
- `FOSSIL-2101`: Anonymous login attempt is missing the |
|
568
|
"anonymousSeed" property (fetched via [the `/json/anonymousPassword` |
|
569
|
request](api-auth.md#login-anonymous)). Note that this is more |
|
570
|
specific form of `FOSSIL-3002`. |
|
571
|
|
|
572
|
|
|
573
|
ONLY FOR TESTING purposes should the remaning 210X sub-codes be |
|
574
|
enabled (they are potentially security-relevant, in that the client |
|
575
|
knows which part of the request was valid/invalid): |
|
576
|
|
|
577
|
- `FOSSIL-2102`: Name not supplied in login request |
|
578
|
- `FOSSIL-2103`: Password not supplied in login request |
|
579
|
- `FOSSIL-2104`: No name/password match found |
|
580
|
|
|
581
|
|
|
582
|
**`FOSSIL-3000`: Usage Error Category** |
|
583
|
|
|
584
|
- `FOSSIL-3001`: Invalid argument/parameter type(s) or value(s) in |
|
585
|
request |
|
586
|
- `FOSSIL-3002`: Required argument(s)/parameter(s) missing from |
|
587
|
request |
|
588
|
- `FOSSIL-3003`: Requested resource identifier is ambiguous (e.g. a |
|
589
|
shortened hash that matches multiple artifacts, an abbreviated |
|
590
|
date that matches multiple commits, etc.) |
|
591
|
- `FOSSIL-3004`: Unresolved resource identifier. A branch/tag/uuid |
|
592
|
provided by client code could not be resolved. This is a special |
|
593
|
case of #3006. |
|
594
|
- `FOSSIL-3005`: Resource already exists and overwriting/replacing is |
|
595
|
not allowed. e.g. trying to create a wiki page or user which already |
|
596
|
exists. FIXME? Consolidate this and resource-not-found into a |
|
597
|
separate category for dumb-down purposes? |
|
598
|
- `FOSSIL-3006`: Requested resource not found. e.g artifact ID, branch |
|
599
|
name, etc. |
|
600
|
|
|
601
|
|
|
602
|
**`FOSSIL-4000`: Database-related Error Category** |
|
603
|
|
|
604
|
- `FOSSIL-4001`: Statement preparation failed. |
|
605
|
- `FOSSIL-4002`: Parameter binding failed. |
|
606
|
- `FOSSIL-4003`: Statement execution failed. |
|
607
|
- `FOSSIL-4004`: Database locked (this is not used anywhere, but |
|
608
|
reserved for future use). |
|
609
|
|
|
610
|
Special-case DB-related errors... |
|
611
|
|
|
612
|
- `FOSSIL-4101`: Fossil Schema out of date (repo rebuild required). |
|
613
|
- `FOSSIL-4102`: Fossil repo db could not be found. |
|
614
|
- `FOSSIL-4103`: Repository db is not valid (possibly corrupt). |
|
615
|
- `FOSSIL-4104`: Check-out not found. This is similar to FOSSIL-4102 |
|
616
|
but indicates that a local checkout is required (but was not |
|
617
|
found). Note that the 4102 gets triggered earlier than this one, and |
|
618
|
so can appear in cases when a user might otherwise expect a 4104 |
|
619
|
error. |
|
620
|
|
|
621
|
|
|
622
|
Some of those error codes are of course "too detailed" for the client to |
|
623
|
do anything with (e.g.. 4001-4004), but their intention is to make it |
|
624
|
easier for Fossil developers to (A) track down problems and (B) support |
|
625
|
clients who report problems. If a client reports, "I get a FOSSIL-4000, |
|
626
|
how can I fix it?" then the developers/support personnel can't say much |
|
627
|
unless they know if it's a 4001, 4002, 4003, 4004, or 4101 (in which |
|
628
|
case they can probably zero in on the problem fairly quickly, since they |
|
629
|
know which API call triggered it and they know (from the error code) the |
|
630
|
general source of the problem). |
|
631
|
|
|
632
|
## Why Standard/Immutable Result Codes are Important |
|
633
|
|
|
634
|
- They are easily internationalized (i.e. associated with non-English |
|
635
|
error text) |
|
636
|
- Clients may be able to add automatic retry strategies for certain |
|
637
|
problem types by examining the result code. e.g. if fossil returns a |
|
638
|
locking or timeout error \[it currently does no special |
|
639
|
timeout/locking handling, by the way\] the client could re-try, |
|
640
|
whereas a usage error cannot be sensibly retried with the same |
|
641
|
inputs. |
|
642
|
- The "category" structure described above allows us some degree of |
|
643
|
flexibility in how detailed the reported errors are reported. |
|
644
|
- While the string prefix "FOSSIL-" on the error codes may seem |
|
645
|
superfluous, it has one minor *potential* advantage on the client |
|
646
|
side: when managing several unrelated data sources, these error |
|
647
|
codes can be immediately identified (by higher-level code which may |
|
648
|
be ignorant of the data source) as having come from the fossil API. |
|
649
|
Think "ORA-111" vs. "111". |
|
650
|
|