From 0542c604661b1f2a1c2a397b0a2765030fe53272 Mon Sep 17 00:00:00 2001 From: Tim Abbott Date: Sat, 20 Jun 2020 19:03:51 -0700 Subject: [PATCH] docs: Do a general update pass on OpenAPI developer docs. --- docs/documentation/api.md | 87 ++++++++++++++++++++++------------- docs/documentation/openapi.md | 38 +++++++-------- 2 files changed, 75 insertions(+), 50 deletions(-) diff --git a/docs/documentation/api.md b/docs/documentation/api.md index e1c8152f7c..bf44c3decc 100644 --- a/docs/documentation/api.md +++ b/docs/documentation/api.md @@ -1,10 +1,28 @@ # Documenting REST API endpoints This document explains the system for documenting [Zulip's REST -API](https://zulip.com/api/rest). This documentation is an -essential resource both for users and the developers of Zulip's mobile -and terminal apps. We carefully designed a system for both displaying -it and helping ensure it stays up to date as Zulip's API changes. +API](https://zulip.com/api/rest). + +Zulip's API documentation is an essential resource both for users and +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: @@ -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 written using the markdown framework that powers our [user 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 Python API documentation (`zerver/openapi/python_examples.py`; run via `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 wide range of possible typos and other bugs in the API 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 (`templates/zerver/help/include/rest-endpoints.md`) in the broader /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 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 -At the top of any REST endpoint documentation page, you'll want to -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 +Displayed at the top of any REST endpoint documentation page, this +should explain what the endpoint does in clear English. Include +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. -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 -`description` field in `zerver/openapi/zulip.yaml`; currently, the -`description` section in `zulip.yaml` is not used for anything. +These sections should often contain a link to the documentation of the +relevant feature in `/help/`. ### Usage examples @@ -89,12 +117,7 @@ writes a Markdown file block that looks something like this: {end_tabs} ``` -For JavaScript and `curl` examples, we just have the example right -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]. +#### Writing Python examples For the Python examples, you'll write the example in `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}` wherever that string appears in the API documentation. -### Arguments +### Parameters -We have a separate Markdown extension to document the arguments that -an API endpoint expects. You'll see this in files like +We have a separate Markdown extension to document the parameters that +an API endpoint supports. You'll see this in files like `templates/zerver/api/render-message.md` via the following Markdown directive (implemented in `zerver/lib/bugdown/api_arguments_table_generator.py`): @@ -194,11 +217,15 @@ above. that endpoint in `zerver/views/`, and inspect its arguments 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/test-backend zerver/tests/test_openapi.py`; this test compares your documentation against the code and can find many common 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 @@ -269,15 +296,11 @@ it? There's several major benefits to this system: of manual management. * Every Zulip server can host correct API documentation for its 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 - 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). -* 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 -state of third-party tools improves, we don't need to redo most of the -actual documentation work in order to migrate tools. +Using the standard OpenAPI format gives us flexibility, though; if we +later choose to migrate to third-party tools, we don't need to redo +the actual documentation work in order to migrate tools. diff --git a/docs/documentation/openapi.md b/docs/documentation/openapi.md index a6ba60a946..a50ffa3a4a 100644 --- a/docs/documentation/openapi.md +++ b/docs/documentation/openapi.md @@ -1,27 +1,31 @@ # OpenAPI configuration -The [OpenAPI](https://swagger.io/specification/) (formerly known as -Swagger) specification is a standardized way to describe how an API -functions. This description then can then be used by any tool that -supports the standard. +[OpenAPI][openapi-spec] is a popular format for describing an API. An +OpenAPI file can be used by various tools to generate documentation +for the API or even basic client-side bindings for dozens of +programming languages. -Zulip uses the Swagger spec to generate an API reference from the -`zulip.yaml` file. This page is a basic introduction to the format of -this file and how to add content to it. +Zulip's API is described in `zerver/openapi/zulip.yaml`. Our aim is +for that file to fully describe every endpoint in the Zulip API, and +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 -may contain other objects, or reference objects defined +In an OpenAPI Swagger file, every configuration section is an object. +Objects may contain other objects, or reference objects defined elsewhere. Larger API specifications may be split into multiple -files. There are more types of objects than mentioned here, you can -find the complete details at -[Swagger/OpenAPI specification page](https://swagger.io/specification/). +files. See the [OpenAPI specification][openapi-spec]. + +[openapi-spec]: https://swagger.io/docs/specification/about/ This library isn't in production use yet, but it is our current plan for how Zulip's API documentation will work. ## 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 other objects (as an alternative to defining everything inline.) 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 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: -``` -Description: This is a single line description. -``` - ``` Description: | This description has multiple lines.