diff --git a/doc/manual/src/contributing/cli-guideline.md b/doc/manual/src/contributing/cli-guideline.md index c82021cc7..3e56d9037 100644 --- a/doc/manual/src/contributing/cli-guideline.md +++ b/doc/manual/src/contributing/cli-guideline.md @@ -391,45 +391,39 @@ status section, but only print warnings and errors. ## Returning future proof JSON -The machine-readable JSON output should be extensible. This means that the -structure of the JSON should support the addition of extra information in many -places. +The schema of JSON output should allow for backwards compatible extension. This section explains how to achieve this. Two definitions are helpful here, because while JSON only defines one "key-value" -object, we use it to cover two use cases: +object type, we use it to cover two use cases: - - **dictionary**: a map from names to things that all have the same type. In + - **dictionary**: a map from names to value that all have the same type. In C++ this would be a `std::map` with string keys. - **record**: a fixed set of attributes each with their own type. In C++, this - would be represented by a struct. + would be represented by a `struct`. -It is best not to mix these use cases, as that leads to incompatibilities and -other bugs. For example, adding a record field to a dictionary breaks consumers -that assume all JSON object fields to have the same meaning and type. +It is best not to mix these use cases, as that may lead to incompatibilities when the schema changes. For example, adding a record field to a dictionary breaks consumers that assume all JSON object fields to have the same meaning and type. This leads to the following guidelines: - - **The top-level value** (or **root** of the returned data structure) **must be a record**. - Without this rule, it would be impossible to add per-invocation metadata in - a manner that doesn't break existing consumers. + - The top-level (root) value must be a record. - - **The value of a dictionary item must always be a record**. As an example, - suppose a command returns a dictionary where each key is the name of a store - type and each value is itself a dictionary representing settings. + Otherwise, one can not change the structure of a command's output. - - **List items should be records**. For example, a list of strings is not an - extensible type, as any additions will break code that expects a list of - strings. - If the list is unordered and it has a unique key that is a string, consider - a dictionary instead of a list. If the order of the items needs to be - preserved, return a list of records. + - The value of a dictionary item must be a record. - - **Streaming JSON should return records**. An example of a streaming JSON - format is "JSON lines", where multiple JSON values are streamed by putting - each on its own line in a text stream. These JSON values can be considered - top-level values or list items, and they must be records. + Otherwise, the item type can not be extended. -Examples: + - List items should be records. + + Otherwise, one can not change the structure of the list items. + + If the order of the items does not matter, and each item has a unique key that is a string, consider representing the list as a dictionary instead. If the order of the items needs to be preserved, return a list of records. + + - Streaming JSON should return records. + + An example of a streaming JSON format is [JSON lines](https://jsonlines.org/), where each line represents a JSON value. These JSON values can be considered top-level values or list items, and they must be records. + +### Examples ```javascript // bad: all keys must be assumed to be store implementations