summaryrefslogtreecommitdiff
path: root/www/json-api/conventions.md
diff options
context:
space:
mode:
Diffstat (limited to 'www/json-api/conventions.md')
-rw-r--r--www/json-api/conventions.md649
1 files changed, 649 insertions, 0 deletions
diff --git a/www/json-api/conventions.md b/www/json-api/conventions.md
new file mode 100644
index 0000000..f3b470c
--- /dev/null
+++ b/www/json-api/conventions.md
@@ -0,0 +1,649 @@
+# JSON API: General Conventions
+([⬑JSON API Index](index.md))
+
+Jump to:
+
+* [JSON Property Naming](#property-names)
+* [HTTP GET Requests](#http-get)
+* [HTTP POST Requests](#http-post)
+ * [POST Request Envelope](#request-envelope)
+* [Request Parameter Data Types](#request-param-types)
+* [Response Envelope](#response-envelope)
+* [HTTP Response Headers](#http-response-header)
+* [CLI vs. HTTP Mode](#cli-vs-http)
+* [Simulating POSTed data](#simulating-post-data)
+* [Indentation/Formatting of JSON Output](#json-indentation)
+* [JSONP](#jsonp)
+* [API Result Codes](#result-codes)
+
+---
+
+<a id="property-names"></a>
+# JSON Property Naming
+
+Since most JSON usage conventionally happens in JavaScript
+environments, this API has (without an explicit decision ever having
+been made) adopted the ubiquitous JavaScript convention of
+`camelCaseWithStartingLower` for naming properties in JSON objects.
+
+<a id="http-get"></a>
+# HTTP GET Requests
+
+Many (if not most) requests can be made via simple GET requests, e.g. we
+*could* use any of the following patterns for a hypothetical JSON-format
+timeline:
+
+- `https://..../timeline/json`
+- `/timeline?format=json`
+- `/timeline?json=1`
+- `/timeline.json`
+- `/json/timeline?...options...`
+
+The API settled on the `/json/...` convention, primarily because it
+simplifies dispatching and argument-handling logic compared to the
+`/[.../]foo.json` approach. Using `/json/...` allows us to unify that
+logic for all JSON sub-commands, for both CLI and HTTP modes.
+
+<a id="http-post"></a>
+# HTTP Post Requests
+
+Certain requests, mainly things like editing checkin messages and
+committing new files entirely, require POST data. This is fundamentally
+very simple to do - clients post plain/unencoded JSON using a common
+wrapper envelope which contains the request-specific data to submit as
+well as some request-independent information (like authentication data).
+
+<a id="request-envelope"></a>
+## POST Request Envelope
+
+POST requests are sent to the same URL as their GET counterpart (if any,
+else their own path), and are sent as plain-text/unencoded JSON wrapped
+in a common request envelope with the following properties:
+
+- `requestId`: Optional arbitrary JSON value, not used by fossil, but
+ returned as-is in responses.
+- `command`: Provides a secondary mechanism for specifying which JSON
+ command should be run. A request path of /json/foo/bar is equivalent
+ to a request with path=/json and command=foo/bar. Note that subpaths
+ do not work this way. e.g. path=/json/foo, command=bar will not
+ work, but path=/json, command=foo/bar will. This option is
+ particularly useful when generating JSON for piping in to CLI mode,
+ but it also has some response-dispatching uses on the client side.
+- `authToken`: Authentication token. Created by a login
+ request. Determines what access rights the user has, and any given
+ request may require specific rights. In principle this is required
+ by any request which needs non-guest privileges, but cookie-aware
+ clients do not manually need to track this (it is managed as a
+ cookie by the agent/browser).
+ - Note that when accessing fossil over a local server instance
+ which was started with the `--localauth` flag, the `authToken`
+ will be ignored and need not be sent with any requests. The user
+ will automatically be given full privileges, as if they were
+ using CLI mode.
+- `payload`: Command-specific parameters. Most can optionally come in
+ via GET parameters, but those taking complex structures expect them
+ to be placed here.
+- `indent`: Optionally specifies indentation for the output. 0=no
+ indention. 1=a single TAB character for each level of
+ indentation. >1 means that many spaces per level. e.g. indent=7
+ means to indent 7 spaces per object/array depth level. cson also
+ supports other flags for fine-tuning the output spacing, and adding
+ them to this interface might be interesting at some
+ point. e.g. whether or not to add a newline to the output. CLI mode
+ adds extra indentation by default, whereas CGI/server modes produce
+ unindented output by default.
+- `jsonp`: Optional String (client function name). Requests which
+ include this will be returned with `Content-Type
+ application/javascript` and will be wrapped up in a function call
+ using the given name. e.g. if `jsonp=foo` then the result would look like:\
+`foo( {...the response envelope...} )`
+
+The API allows most of those (normally all but the payload) to come in
+as either GET parameters or properties of the top-level POSTed request
+JSON envelope, with GET taking priority over POST. (Reminder to self: we
+could potentially also use values from cookies. Fossil currently only
+uses 1 cookie (the login token), and I'd prefer to keep it that way.)
+
+POST requests without such an envelope will be rejected, generating a
+Fossil/JSON error response (as opposed to an HTTP error response). GET
+requests, by definition, never have an envelope.
+
+POSTed client requests *must* send a Content-Type header of either
+`application/json` , `application/javascript`, or `text/plain`, or the
+JSON-handling code will never see the POST data. The POST handler
+optimistically assumes that type `text/plain` "might be JSON", since
+`application/json` is a newer convention which many existing clients
+do not use (as of the time these docs were written, back in 2011).
+
+## POST Envelope vs. `POST.payload`
+
+
+When this document refers to POST data, it is referring to top-level
+object in JSON-format POSTed input data. When we say `POST.payload` we
+refer to the "payload" property of the POST data. While fossil's core
+handles *form-urlencoded* POST data, if such data is sent in then
+parsing it as JSON cannot succeed, which means that (at worst) the
+JSON-mode bits will "not see" any POST data. Data POSTed to the JSON API
+must be sent non-form-urlencoded (i.e. as plain text).
+
+Framework-level configuration options are always set via the top-level
+POST envelope object or GET parameters. Request-specific options are set
+either in `POST.payload` or GET parameters (though the former is required
+in some cases). Here is an example which demonstrates the possibly
+not-so-obvious difference between the two types of options (framework
+vs. request-specific):
+
+```json
+{
+"requestId":"my request", // standard envelope property (optional)
+"command": "timeline/wiki", // also standard
+"indent":2, // output indention is a framework-level option
+"payload":{ // *anything* in the payload is request-specific
+ "limit":1
+}
+}
+```
+
+When a given parameter is set in two places, e.g. GET and POST, or
+POST-from-a-file and CLI parameters, which one takes precedence
+depends on the concrete command handler (and may be unspecified). Most
+will give precedence to CLI and GET parameters, but POSTed values are
+technically preferred for non-string data because no additional "type
+guessing" or string-to-whatever conversion has to be made (GET/CLI
+parameters are *always* strings, even if they look like a number or
+boolean).
+
+
+<a id="request-param-types"></a>
+# Request Parameter Data Types
+
+When parameters are sent in the form of GET or CLI arguments, they are
+inherently strings. When they come in from JSON they keep their full
+type (boolean, number, etc.). All parameters in this API specify what
+*type* (or types) they must (or may) be. For strings, there is no
+internal conversion/interpretation needed for GET- or CLI-provided
+parameters, but for other types we sometimes have to convert strings to
+other atomic types. This section describes how those string-to-whatever
+conversions behave.
+
+No higher-level constructs, e.g. JSON **arrays** or **objects**, are
+accepted in string form. Such parameters must be set in the POST
+envelope or payload, as specified by the specific API.
+
+This API does not currently use any **floating-point** parameters, but
+does return floating-point results in a couple of places.
+
+For **integer** parameters we use a conventional string-to-int algorithm
+and assume base 10 (analog to atoi(3)). The API may err on the side of
+usability when given technically invalid values. e.g. "123abc" will
+likely be interpreted as the integer 123. No APIs currently rely on
+integer parameters with more than 32 bits (signedness is call-dependent
+but few, if any, use negative values).
+
+**Boolean** parameters are a bit schizophrenic...
+
+In **CLI mode**, boolean flags do not have a value, per se, and thus
+require no string-to-bool conversion. e.g.
+`fossil foo -aBoolOpt -non-bool-opt value`.
+
+Those which arrive as strings via **GET parameters** treat any of the
+following as true: a string starting with a character in the set
+`[1-9tT]`. All other string values are considered to be false for this
+purpose.
+
+Those which are part of the **POST data** are normally (but not always -
+it depends on the exact context) evaluated as the equivalent of
+JavaScript booleans. e.g. if we have `POST.envelope.foo="f"`, and evaluate
+it as a JSON boolean (as opposed to a string-to-bool conversion), the
+result will be true because the underlying JSON API follows JavaScript
+semantics for any-type-to-bool conversions. As long as clients always
+send "proper" booleans in their POST data, the difference between
+GET/CLI-provided booleans should never concern them.
+
+TODO: consider changing the GET-value-to-bool semantics to match the JS
+semantics, for consistency (within the JSON API at least, but that might
+cause inconsistencies vis-a-vis the HTML interface).
+
+<a id="response-envelope"></a>
+# Response Envelope
+
+Every response comes in the form of an HTTP response or (in CLI mode)
+JSON sent to stdout. The body of the response is a JSON object following
+a common envelope format. The envelope has the following properties:
+
+
+- `fossil`: Fossil server version string. This property is basically
+ "the official response envelope marker" - if it is set, clients can
+ "probably safely assume" that the object indeed came from one of the
+ Fossil/JSON APIs. This API never creates responses which do not
+ contain this property.
+- `requestId`: Only set if the request contained it, and then it is
+ echoed back to the caller as-is. This can be used to determine
+ (client-side) which request a given response is coming in for
+ (assuming multiple asynchronous requests are pending). In practice
+ this generally isn’t needed because response handling tends to be
+ done by closures associated with the original request object (at
+ least in JavaScript code). In languages without closures it might
+ have some use. It may be any legal JSON value - it need not be
+ confined to a string or number.
+- `resultCode`: Standardized result code string in the form
+ `FOSSIL-####`. Only error responses contain a `resultCode`.
+- `resultText`: Possibly a descriptive string, possibly
+ empty. Supplements the resultCode, but can also be set on success
+ responses (but normally isn't). Clients must not rely on any
+ specific values being set here.
+- `payload`: Request-specific response payload (data type/structure is
+ request-specific). The payload is never set for error responses,
+ only for success responses (and only those which actually have a
+ payload - not all do).
+- `timestamp`: Response timestamp (GMT Unix Epoch). We use seconds
+ precision because I did not know at the time that Fossil actually
+ records millisecond precision.
+- `payloadVersion`: Not initially needed, but reserved for future use
+ in maintaining version compatibility when the format of a given
+ response type's payload changes. If needed, the "first version"
+ value is assumed to be 0, for semantic [near-]compatibility with the
+ undefined value clients see when this property is not set.
+- `command`: Normalized form of the command being run. It consists of
+ the "command" (non-argument) parts of the request path (or CLI
+ positional arguments), excluding the initial "/json/" part. e.g. the
+ "command" part of "/json/timeline/checkin?a=b" (CLI: json timeline
+ checkin...) is "timeline/checkin" (both in CLI and HTTP modes).
+- `apiVersion`: Not yet used, but reserved for a numeric value which
+ represents the JSON API's version (which can be used to determine if
+ it has a given feature or not). This will not be implemented until
+ it's needed.
+- `warnings`: Reserved for future use as a standard place to put
+ non-fatal warnings in responses. Will be an array but the warning
+ structure/type is not yet specified. Intended primarily as a
+ debugging tool, and will "probably not" become part of the public
+ client interface.
+- `g`: Fossil administrators (those with the "a" or "s" permissions)
+ may set the `debugFossilG` boolean request parameter (CLI:
+ `--json-debug-g`) to enable this property for any given response. It
+ contains a good deal of the server-side internal state at the time
+ the response was generated, which is often useful in debuggering
+ problems. Trivia: it is called "g" because that's the name of
+ fossil's internal global state object.
+- `procTimeMs`: For debugging only - generic clients must not rely on
+ this property. Contains the number of milliseconds the JSON command
+ processor needed to dispatch and process the command. TODO: move the
+ timer into the fossil core so that we can generically time its
+ responses and include the startup overhead in the time calculation.
+
+
+
+<a id="http-response-header"></a>
+# HTTP Response Headers
+
+The Content-Type HTTP header of a response will be either
+application/json, application/javascript, or text/plain, depending on
+whether or not we are in JSONP mode or (failing that) the contents of
+the "Accept" header sent in the request. The response type will be
+text/plain if it cannot figure out what to do. The response's
+Content-Type header *may* contain additional metadata, e.g. it might
+look like: application/json; charset=utf-8
+
+Apropos UTF-8: note that JSON is, by definition, Unicode and recommends
+UTF-8 encoding (which is what we use). That means if your console cannot
+handle UTF-8 then using this API in CLI mode might (depending on the
+content) render garbage on your screen.
+
+
+<a id="cli-vs-http"></a>
+# CLI vs. HTTP Mode
+
+CLI (command-line interface) and HTTP modes (CGI and standalone server)
+are consolidated in the same implementations and behave essentially
+identically, with only minor exceptions.
+
+An HTTP path of `/json/foo` translates to the CLI command `fossil json
+foo`. CLI mode takes options in the fossil-convention forms (e.g. `--foo 3`
+or `-f 3`) whereas HTTP mode takes them via GET/POST data (e.g. `?foo=1`).
+(Note that per long-standing fossil convention CLI parameters taking a
+value do not use an equal sign before the value!)
+
+For example:
+
+- HTTP: `/json/timeline/wiki?after=2011-09-01&limit=3`
+- CLI: `fossil json timeline wiki --after 2011-09-01 --limit 3`
+
+Some commands may only work in one mode or the other (for various
+reasons). In CLI mode the user automatically has full setup/admin
+access.
+
+In HTTP mode, request-specific options can also be specified in the
+`POST.payload` data, and doing so actually has an advantage over
+specifying them as URL parameters: posting JSON data retains the full
+type information of the values, whereas GET-style parameters are always
+strings and must be explicitly type-checked/converted (which may produce
+unpredictable results when given invalid input). That said, oftentimes
+it is more convenient to pass the options via URL parameters, rather
+than generate the request envelope and payload required by POST
+requests, and the JSON API makes some extra effort to treat GET-style
+parameters type-equivalent to their POST counterparts. If a property
+appears in both GET and `POST.payload`, GET-style parameters *typically*
+take precedence over `POST.payload` by long-standing convention (=="PHP
+does it this way by default").
+
+(That is, however, subject to eventual reversal because of the
+stronger type safety provided by POSTed JSON. Philosophically
+speaking, though, GET *should* take precedence, in the same way that
+CLI-provided options conventionally override app-configuration-level
+options.)
+
+One notable functional difference between CLI and HTTP modes is that in
+CLI mode error responses *might* be accompanied by a non-0 exit status
+(they "should" always be, but there might be cases where that does not
+yet happen) whereas in HTTP mode we always try to exit with code 0 to
+avoid generating an HTTP 500 ("internal server error"), which could keep
+the JSON response from being delivered. The JSON code only intentionally
+allows an HTTP 500 when there is a serious internal error like
+allocation or assertion failure. HTTP clients are expected to catch
+errors by evaluating the response object, not the HTTP result code.
+
+<a id="simulating-post-data"></a>
+# Simulating POSTed data
+
+We have a mechanism to feed request data to CLI mode via
+files (simulating POSTed data), as demonstrated in this example:
+
+```console
+$ cat in.json
+{ "command": "timeline/wiki", "indent":2, "payload":{"limit":1}}
+$ fossil json --json-input in.json # use filename - for stdin
+```
+
+The above is equivalent to:
+
+```console
+$ echo '{"indent":2, "payload":{"limit":1}}' \
+ | fossil json timeline wiki --json-input -
+```
+
+Note that the "command" JSON parameter is only checked when no json
+subcommand is provided on the CLI or via the HTTP request path. Thus we
+cannot pass the CLI args "json timeline" in conjunction with a "command"
+string of "wiki" this way.
+
+***HOWEVER...***
+
+Much of the existing JSON code was written before the `--json-input`
+option was possible. Because of this, there might be some
+"misinteractions" when providing request-specific options via *both*
+CLI options and simulated POST data. Those cases will eventually be
+ironed out (with CLI options taking precedence). Until then, when
+"POSTing" data in CLI mode, for consistent/predictible results always
+provide any options via the JSON request data, not CLI arguments. That
+said, there "should not" be any blatant incompatibilities, but some
+routines will prefer `POST.payload` over CLI/GET arguments, so there
+are some minor inconsistencies across various commands with regards to
+which source (POST/GET/CLI) takes precedence for a given option. The
+precedence "should always be the same," but currently cannot be due to
+core fossil implementation details (the internal consolidation of
+GET/CLI/POST vars into a single set).
+
+
+<a id="json-indentation"></a>
+# Indentation/Formatting of JSON Output
+
+CLI mode accepts the `--indent|-I #` option to set the indention level
+and HTTP mode accepts `indent=#` as a GET/POST parameter. The semantics
+of the indention level are derived from the underlying JSON library and
+have the following meanings: 0 (zero) or less disables all superfluous
+indentation (this is the default in HTTP mode). A value of 1 uses 1 hard
+TAB character (ASCII 0x09) per level of indention (the default in CLI
+mode). Values greater than 1 use that many whitespaces (ASCII 32d) per
+level of indention. e.g. a value of 7 uses 7 spaces per level of
+indention. There is no way to specify one whitespace per level, but if
+you *really* want one whitespace instead of one tab (same data size) you
+can filter the output to globally replace ASCII 9dec (TAB) with ASCII
+32dec (space). Because JSON string values *never* contain hard tabs
+(they are represented by `\t`) there is no chance that such a global
+replacement will corrupt JSON string contents - only the formatting will
+be affected.
+
+Potential TODO: because extraneous indention "could potentially" be used
+as a form of DoS, the option *might* be subject to later removal from HTTP
+mode (in CLI it's fine).
+
+In HTTP mode no trailing newline is added to the output, whereas in CLI
+mode one is normally appended (exception: in JSONP mode no newline is
+appended, to (rather pedantically and arbitraily) allow the client to
+add a semicolon at the end if he likes). There is currently no option to
+control the newline behaviour, but the underlying JSON code supports
+this option, so adding it to this API is just a matter of adding the
+CLI/HTTP args for it.
+
+Pedantic note: internally the indention level is stored as a single
+byte, so giving large indention values will cause harmless numeric
+overflow (with only cosmetic effects), meaning, e.g., 257 will overflow
+to the value 1.
+
+Potential TODO: consider changing cson's indention mechanism to use a
+*signed* number, using negative values for tabs and positive for
+whitespace count (or the other way around). This would require more
+doc changes than code changes :/.
+
+
+<a id="jsonp"></a>
+# JSONP
+
+The API supports JSONP-style output. The caller specifies the callback
+name and the JSON response will be wrapped in a function call to that
+name. For HTTP mode pass the `jsonp=string` option (via GET or POST
+envelope) and for CLI use `--jsonp string`.
+
+For example, if we pass the JSONP name `myCallback` then a response will
+look like:
+
+```js
+myCallback({...response...})
+```
+
+Note that fossil does not evaluate the callback name itself, other than
+to verify that it is-a string, so "garbage in, garbage out," and all
+that. (Remember that CLI and GET parameters are *always* strings, even
+if they *look* like numbers.)
+
+
+<a id="result-codes"></a>
+# API Result Codes
+
+Result codes are strings which tell the client whether or not a given
+API call succeeded or failed, and if it failed *perhaps* some hint as to
+why it failed.
+
+The result code is available via the resultCode property of every
+*error* response envelope. Since having a result code value for success
+responses is somewhat redundant, success responses contain no resultCode
+property. In practice this simplifies error checking on the client side.
+
+The codes are strings in the form `FOSSIL-####`, where `####` is a
+4-digit integral number, left-padded with zeros. The numbers follow
+these conventions:
+
+- The number 0000 is reserved for the "not an error" (OK) case. Since
+ success responses do not contain a result code, clients won't see
+ this value (except in documentation).
+- All numbers with a leading 0 are reserved for *potential* future use
+ in reporting non-fatal warnings.
+- Despite *possibly* having leading zeros, the numbers are decimal,
+ not octal. Script code which uses eval() or similar to produce
+ integers from them may need to take that into account.
+- The 1000ths and 100ths places of the number describe the general
+ category of the error, e.g. authentication- vs. database- vs. usage
+ errors. The 100ths place is more specific than the 1000ths place,
+ allowing two levels of sub-categorization (which "should be enough"
+ for this purpose). This separation allows the server administrator
+ to configure the level of granularity of error reporting. e.g. some
+ admins consider error messages to be security-relevant and like to
+ "dumb them down" on their way to the client, whereas developers
+ normally want to see very specific error codes when tracking down a
+ problem. We can offer a configuration option to "dumb down" error
+ codes to their generic category by simply doing a modulo 100
+ (or 1000) against the native error code number. e.g. FOSSIL-1271
+ could (via a simple modulo) be reduced to FOSSIL-1200 or
+ FOSSIL-1000, depending on the paranoia level of the sysadmin. I have
+ tried to order the result code numbers so that a dumb-down level of
+ 2 provides reasonably usable results without giving away too much
+ detail to malicious clients.\
+ (**TODO:** `g.json.errorDetailParanoia` is used to set the
+ default dumb-down level, but it is currently set at compile-time.
+ It needs to be moved to a config option. We have a chicken/egg scenario
+ with error reporting and db access there (where the config is
+ stored).)
+- Once a number is assigned to a given error condition (and actually
+ used somewhere), it may not be changed/redefined. JSON clients need
+ to be able to rely on stable result codes in order to provide
+ adequate error reporting to their clients, and possibly for some
+ error recovery logic as well (i.e. to decide whether to abort or
+ retry).
+
+The *tentative* list of result codes is shown in the following table.
+These numbers/ranges are "nearly arbitrarily" chosen except for the
+"special" value 0000.
+
+**Maintenance reminder:** these codes are defined in
+[`src/json_detail.h`](/finfo/src/json_detail.h) (enum
+`FossilJsonCodes`) and assigned default `resultText` values in
+[`src/json.c:json_err_cstr()`](/finfo/src/json.c). Changes there need
+to be reflected here (and vice versa). Also, we have assertions in
+place to ensure that C-side codes are in the range 1000-9999, so do
+not just go blindly change the numeric ranges used by the enum.
+
+
+**`FOSSIL-0###`: Non-error Category**
+
+- `FOSSIL-0000`: Success/not an error. Succesful responses do not
+ contain a resultCode, so clients should never see this.
+- `FOSSIL-0###`: Reserved for potential future use in reporting
+ non-fatal warnings.
+
+
+
+**`FOSSIL-1000`: Generic Errors Category**
+
+- `FOSSIL-1101`: Invalid request. Request envelope is invalid or
+ missing.
+- `FOSSIL-1102`: Unknown JSON command.
+- `FOSSIL-1103`: Unknown/unspecified error
+- `FOSSIL-1104`: RE-USE
+- `FOSSIL-1105`: A server-side timeout was reached. (i’m not sure we
+ can actually implement this one, though.)
+- `FOSSIL-1106`: Assertion failed (or would have had we
+ continued). Note: if an `assert()` fails in CGI/server modes, the HTTP
+ response will be code 500 (Internal Server Error). We want to avoid
+ that and return a JSON response instead. All of that said - there seems
+ to be little reason to implement this, since assertions are "truly
+ serious" errors.
+- `FOSSIL-1107`: Allocation/out of memory error. This cannot be reasonably
+ reported because fossil aborts if an allocation fails.
+- `FOSSIL-1108`: Requested API is not yet implemented.
+- `FOSSIL-1109`: Panic! Fossil's `fossil_panic()` or `cgi_panic()` was
+ called. In non-JSON HTML mode this produces an HTTP 500
+ error. Clients "should" report this as a potential bug, as it
+ "possibly" indicates that the C code has incorrect argument- or
+ error handling somewhere.
+- `FOSSIL-1110`: Reading of artifact manifest failed. Time to contact
+ your local fossil guru.
+- `FOSSIL-1111`: Opening of file failed (e.g. POST data provided to
+ CLI mode).
+
+
+**`FOSSIL-2000`: Authentication/Access Error Category**
+
+- `FOSSIL-2001`: Privileged request was missing authentication
+ token/cookie.
+- `FOSSIL-2002`: Access to requested resource was denied. Oftentimes
+ the `resultText` property will contain a human-language description of
+ the access rights needed for the given command.
+- `FOSSIL-2003`: Requested command is not available in the current
+ operating mode. Returned in CLI mode by commands which require HTTP
+ mode (e.g. login), and vice versa. FIXME: now that we can simulate
+ POST in CLI mode, we can get rid of this distinction for some of the
+ commands.
+- `FOSSIL-2100`: Login Failed.
+- `FOSSIL-2101`: Anonymous login attempt is missing the
+ "anonymousSeed" property (fetched via [the `/json/anonymousPassword`
+ request](api-auth.md#login-anonymous)). Note that this is more
+ specific form of `FOSSIL-3002`.
+
+
+ONLY FOR TESTING purposes should the remaning 210X sub-codes be
+enabled (they are potentially security-relevant, in that the client
+knows which part of the request was valid/invalid):
+
+- `FOSSIL-2102`: Name not supplied in login request
+- `FOSSIL-2103`: Password not supplied in login request
+- `FOSSIL-2104`: No name/password match found
+
+
+**`FOSSIL-3000`: Usage Error Category**
+
+- `FOSSIL-3001`: Invalid argument/parameter type(s) or value(s) in
+ request
+- `FOSSIL-3002`: Required argument(s)/parameter(s) missing from
+ request
+- `FOSSIL-3003`: Requested resource identifier is ambiguous (e.g. a
+ shortened hash that matches multiple artifacts, an abbreviated
+ date that matches multiple commits, etc.)
+- `FOSSIL-3004`: Unresolved resource identifier. A branch/tag/uuid
+ provided by client code could not be resolved. This is a special
+ case of #3006.
+- `FOSSIL-3005`: Resource already exists and overwriting/replacing is
+ not allowed. e.g. trying to create a wiki page or user which already
+ exists. FIXME? Consolidate this and resource-not-found into a
+ separate category for dumb-down purposes?
+- `FOSSIL-3006`: Requested resource not found. e.g artifact ID, branch
+ name, etc.
+
+
+**`FOSSIL-4000`: Database-related Error Category**
+
+- `FOSSIL-4001`: Statement preparation failed.
+- `FOSSIL-4002`: Parameter binding failed.
+- `FOSSIL-4003`: Statement execution failed.
+- `FOSSIL-4004`: Database locked (this is not used anywhere, but
+ reserved for future use).
+
+Special-case DB-related errors...
+
+- `FOSSIL-4101`: Fossil Schema out of date (repo rebuild required).
+- `FOSSIL-4102`: Fossil repo db could not be found.
+- `FOSSIL-4103`: Repository db is not valid (possibly corrupt).
+- `FOSSIL-4104`: Check-out not found. This is similar to FOSSIL-4102
+ but indicates that a local checkout is required (but was not
+ found). Note that the 4102 gets triggered earlier than this one, and
+ so can appear in cases when a user might otherwise expect a 4104
+ error.
+
+
+Some of those error codes are of course "too detailed" for the client to
+do anything with (e.g.. 4001-4004), but their intention is to make it
+easier for Fossil developers to (A) track down problems and (B) support
+clients who report problems. If a client reports, "I get a FOSSIL-4000,
+how can I fix it?" then the developers/support personnel can't say much
+unless they know if it's a 4001, 4002, 4003, 4004, or 4101 (in which
+case they can probably zero in on the problem fairly quickly, since they
+know which API call triggered it and they know (from the error code) the
+general source of the problem).
+
+## Why Standard/Immutable Result Codes are Important
+
+- They are easily internationalized (i.e. associated with non-English
+ error text)
+- Clients may be able to add automatic retry strategies for certain
+ problem types by examining the result code. e.g. if fossil returns a
+ locking or timeout error \[it currently does no special
+ timeout/locking handling, by the way\] the client could re-try,
+ whereas a usage error cannot be sensibly retried with the same
+ inputs.
+- The "category" structure described above allows us some degree of
+ flexibility in how detailed the reported errors are reported.
+- While the string prefix "FOSSIL-" on the error codes may seem
+ superfluous, it has one minor *potential* advantage on the client
+ side: when managing several unrelated data sources, these error
+ codes can be immediately identified (by higher-level code which may
+ be ignorant of the data source) as having come from the fossil API.
+ Think "ORA-111" vs. "111".