docs: Do a general update pass on OpenAPI developer docs.

This commit is contained in:
Tim Abbott 2020-06-20 19:03:51 -07:00
parent 318bc0ca1e
commit 0542c60466
2 changed files with 75 additions and 50 deletions

View File

@ -1,10 +1,28 @@
# Documenting REST API endpoints # Documenting REST API endpoints
This document explains the system for documenting [Zulip's REST This document explains the system for documenting [Zulip's REST
API](https://zulip.com/api/rest). This documentation is an API](https://zulip.com/api/rest).
essential resource both for users and the developers of Zulip's mobile
and terminal apps. We carefully designed a system for both displaying Zulip's API documentation is an essential resource both for users and
it and helping ensure it stays up to date as Zulip's API changes. for the developers of Zulip's mobile and terminal apps. Our vision is
for the documentation to be sufficiently good that developers of
Zulip's apps should never need to look at the server's implementation
to answer questions about the API's semantics.
To achieve these goals, Zulip leverages the popular OpenAPI format as
the data source to ensure that Zulip's API documentation is correct
and remains so as Zulip's API evolves.
In particular, the top goal for this system is that all mistakes in
verifiable content (i.e. not the English explanations) should cause
the Zulip test suite to fail. This is incredibly important, because
once you notice one error in API documentation, you no longer trust it
to be correct, which ends up wasting the time of its users.
Since it's very difficult to not make little mistakes when writing any
code of untested code, the only good solution to this is a way to test
the documentation. We found dozens of errors in the process of adding
the validation Zulip has today.
Our API documentation is defined by a few sets of files: Our API documentation is defined by a few sets of files:
@ -14,7 +32,9 @@ Our API documentation is defined by a few sets of files:
* The top-level templates live under `templates/zerver/api/*`, and are * The top-level templates live under `templates/zerver/api/*`, and are
written using the markdown framework that powers our [user written using the markdown framework that powers our [user
docs](../documentation/user.md), with some special extensions for docs](../documentation/user.md), with some special extensions for
rendering nice code blocks and example responses. rendering nice code blocks and example responses. We expect to
eventually remove most of these files where it is possible to
fully generate the documentation from the OpenAPI files.
* The text for the Python examples comes from a test suite for the * The text for the Python examples comes from a test suite for the
Python API documentation (`zerver/openapi/python_examples.py`; run via Python API documentation (`zerver/openapi/python_examples.py`; run via
`tools/test-api`). The `generate_code_example` macro will magically `tools/test-api`). The `generate_code_example` macro will magically
@ -22,9 +42,20 @@ Our API documentation is defined by a few sets of files:
This structure ensures that Zulip's API documentation is robust to a This structure ensures that Zulip's API documentation is robust to a
wide range of possible typos and other bugs in the API wide range of possible typos and other bugs in the API
documentation. documentation.
* The JavaScript examples are similarly generated and tested using
`zerver/openapi/javascript_examples.js`.
* The cURL examples are generated and tested using
`zerver/openapi/curl_param_value_generators.py`.
* The REST API index * The REST API index
(`templates/zerver/help/include/rest-endpoints.md`) in the broader (`templates/zerver/help/include/rest-endpoints.md`) in the broader
/api left sidebar (`templates/zerver/api/sidebar_index.md`). /api left sidebar (`templates/zerver/api/sidebar_index.md`).
* We have an extensive set of tests designed to validate that the data
in this file is correct, `zerver/tests/test_openapi.py` compares
every endpoint's accepted parameters in `views` code with those
declared in `zulip.yaml`. And [backend test
suite](../testing/testing-with-django.md) and checks that every API
response served during our extensive backend test suite matches one
the declared OpenAPI schema for that endpoint.
This first section is focused on explaining how the API documentation This first section is focused on explaining how the API documentation
system is put together; when actually documenting an endpoint, you'll system is put together; when actually documenting an endpoint, you'll
@ -52,16 +83,13 @@ The rest of this guide describes how each of these sections works.
### Description ### Description
At the top of any REST endpoint documentation page, you'll want to Displayed at the top of any REST endpoint documentation page, this
explain what the endpoint does in clear English. Include should explain what the endpoint does in clear English. Include
notes on how to use it correctly or what it's good or bad for, with details on how to use it correctly or what it's good or bad for, with
links to any alternative endpoints the user might want to consider. links to any alternative endpoints the user might want to consider.
These sections should almost always contain a link to the
documentation of the relevant feature in `/help/`.
We plan to migrate to storing this description content in the These sections should often contain a link to the documentation of the
`description` field in `zerver/openapi/zulip.yaml`; currently, the relevant feature in `/help/`.
`description` section in `zulip.yaml` is not used for anything.
### Usage examples ### Usage examples
@ -89,12 +117,7 @@ writes a Markdown file block that looks something like this:
{end_tabs} {end_tabs}
``` ```
For JavaScript and `curl` examples, we just have the example right #### Writing Python examples
there in the markdown file. It is **critical** that these examples be
tested manually by copy-pasting the result; it is very easy and very
embarrassing to have typos result in incorrect documentation.
Additionally, JavaScript examples should conform to the coding style
and structure of [Zulip's existing JavaScript examples][javascript-examples].
For the Python examples, you'll write the example in For the Python examples, you'll write the example in
`zerver/openapi/python_examples.py`, and it'll be run and verified `zerver/openapi/python_examples.py`, and it'll be run and verified
@ -141,10 +164,10 @@ substitute it in place of
`{generate_code_example(python)|/messages/render:post|example}` `{generate_code_example(python)|/messages/render:post|example}`
wherever that string appears in the API documentation. wherever that string appears in the API documentation.
### Arguments ### Parameters
We have a separate Markdown extension to document the arguments that We have a separate Markdown extension to document the parameters that
an API endpoint expects. You'll see this in files like an API endpoint supports. You'll see this in files like
`templates/zerver/api/render-message.md` via the following Markdown `templates/zerver/api/render-message.md` via the following Markdown
directive (implemented in directive (implemented in
`zerver/lib/bugdown/api_arguments_table_generator.py`): `zerver/lib/bugdown/api_arguments_table_generator.py`):
@ -194,11 +217,15 @@ above.
that endpoint in `zerver/views/`, and inspect its arguments that endpoint in `zerver/views/`, and inspect its arguments
declared using `REQ`. declared using `REQ`.
You can check your formatting using two helpful tools. You can check your formatting using these helpful tools.
* `tools/check-openapi` will verify the syntax of `zerver/openapi/zulip.yaml`. * `tools/check-openapi` will verify the syntax of `zerver/openapi/zulip.yaml`.
* `tools/test-backend zerver/tests/test_openapi.py`; this test compares * `tools/test-backend zerver/tests/test_openapi.py`; this test compares
your documentation against the code and can find many common your documentation against the code and can find many common
mistakes in how arguments are declared. mistakes in how arguments are declared.
* `test-backend`: The full Zulip backend test suite will fail if
any actual API responses generated by the tests don't match your
defined OpenAPI schema. Use `test-backend --rerun` for a fast
edit/refresh cycle when debugging.
[rest-api-tutorial]: ../tutorials/writing-views.html#writing-api-rest-endpoints [rest-api-tutorial]: ../tutorials/writing-views.html#writing-api-rest-endpoints
@ -269,15 +296,11 @@ it? There's several major benefits to this system:
of manual management. of manual management.
* Every Zulip server can host correct API documentation for its * Every Zulip server can host correct API documentation for its
version, with the key variables (like the Zulip server URL) already version, with the key variables (like the Zulip server URL) already
pre-susbtituted for the user. pre-sustituted for the user.
* We're able to share implementation language and visual styling with * We're able to share implementation language and visual styling with
our Helper Center, which is especially useful for the extensive our Help Center, which is especially useful for the extensive
non-REST API documentation pages (e.g. our bot framework). non-REST API documentation pages (e.g. our bot framework).
* Open source systems for displaying OpenAPI documentation (such as
Swagger) have poor UI, whereas Cloud systems that accept OpenAPI
data, like readme.io, make the above things much more difficult to
manage.
Using the standard OpenAPI format gives us flexibility, though; if the Using the standard OpenAPI format gives us flexibility, though; if we
state of third-party tools improves, we don't need to redo most of the later choose to migrate to third-party tools, we don't need to redo
actual documentation work in order to migrate tools. the actual documentation work in order to migrate tools.

View File

@ -1,27 +1,31 @@
# OpenAPI configuration # OpenAPI configuration
The [OpenAPI](https://swagger.io/specification/) (formerly known as [OpenAPI][openapi-spec] is a popular format for describing an API. An
Swagger) specification is a standardized way to describe how an API OpenAPI file can be used by various tools to generate documentation
functions. This description then can then be used by any tool that for the API or even basic client-side bindings for dozens of
supports the standard. programming languages.
Zulip uses the Swagger spec to generate an API reference from the Zulip's API is described in `zerver/openapi/zulip.yaml`. Our aim is
`zulip.yaml` file. This page is a basic introduction to the format of for that file to fully describe every endpoint in the Zulip API, and
this file and how to add content to it. for the Zulip test suite to fail should the API every change without a
corresponding adjustment to the documentation. In particular,
essentially all content in Zulip's [REST API
documentation](../documentation/api.md) is generated from our OpenAPI
file.
In a Swagger file, every configuration section is an object. Objects In an OpenAPI Swagger file, every configuration section is an object.
may contain other objects, or reference objects defined Objects may contain other objects, or reference objects defined
elsewhere. Larger API specifications may be split into multiple elsewhere. Larger API specifications may be split into multiple
files. There are more types of objects than mentioned here, you can files. See the [OpenAPI specification][openapi-spec].
find the complete details at
[Swagger/OpenAPI specification page](https://swagger.io/specification/). [openapi-spec]: https://swagger.io/docs/specification/about/
This library isn't in production use yet, but it is our current plan This library isn't in production use yet, but it is our current plan
for how Zulip's API documentation will work. for how Zulip's API documentation will work.
## Working with the `zulip.yaml` file ## Working with the `zulip.yaml` file
A Swagger specification file has three general parts: information and An OpenAPI specification file has three general parts: information and
configuration, endpoint definitions, and object schemas referenced by configuration, endpoint definitions, and object schemas referenced by
other objects (as an alternative to defining everything inline.) other objects (as an alternative to defining everything inline.)
References can either specify an individual object, using `$ref:`, or References can either specify an individual object, using `$ref:`, or
@ -173,14 +177,12 @@ correct.
* A single `|` (pipe) character begins a multi-line description on the * A single `|` (pipe) character begins a multi-line description on the
next line. Single spaced lines (one newline at the end of each) are next line. Single spaced lines (one newline at the end of each) are
joined. Use an extra blank line for a paragraph break. joined. Use an extra blank line for a paragraph break. We prefer
to use this format for all descriptions because it doesn't require
extra effort to expand.
### Examples: ### Examples:
```
Description: This is a single line description.
```
``` ```
Description: | Description: |
This description has multiple lines. This description has multiple lines.