Documenting REST API
How the CHT REST API reference documentation is built, published, and rendered
The REST API reference page renders an OpenAPI 3.1 specification produced by cht-core.
Pipeline overview
- OpenAPI configuration lives alongside the route definitions in cht-core as JSDoc comments on the API controller functions.
- The
build-documentationnpm script compiles, lints, and validates the annotations, writing the result toshared-libs/cht-datasource/docs/openapi.json. - A GitHub Action in cht-core publishes that
openapi.jsonon every commit to themasterbranch. - The Swagger shortcode on the REST API reference page loads the latest published version by default.
Adding or updating API endpoints
When adding or modifying an endpoint in cht-core, the OpenAPI configuration for the endpoint must be updated in the same pull request. The controller function for the endpoint must have a JSDoc comment, annotated with @openapi, containing the yaml structure of the OpenAPI configuration for that operation. Once the configuration has been added to the comment:
- Run
npm run build-documentationfrom the cht-core repository root. - Review the linter output and fix any validation errors.
- Commit the changes to the controller file. (Do not commit the generated
shared-libs/cht-datasource/docs/openapi.jsonfile.)
Once the pull request merges to master, the cht-core GitHub Action publishes the updated spec. The docs site automatically picks up the updated version. No changes to cht-docs are necessary.
Tags
On the REST API reference page, the operations are grouped according to their configured tags value. Conventionally, each operation must have one tags value. Each new tag that is used must also be defined with a name and description in the top-level tags configuration. Conventionally, this is done in a top-level JSDoc comment in the controller file.
CHT-specific extensions
The Swagger shortcode renders two OpenAPI specification extensions as badges on each operation:
x-permissions— the permissions required to call the endpoint. The value is an object withhasAll(all permissions required) and/orhasAny(at least one required). For example:{ "x-permissions": { "hasAll": ["can_view_contacts"], "hasAny": ["can_edit", "can_create_people"] } }x-since— the CHT version in which the endpoint was added, as a string (for example,"v4.10.0").
Including schema references in OpenAPI configuration
Special $ref values can be used in the OpenAPI yaml config to reference reusable component schemas. This prevents excessive duplication of schema definitions. Referenced schema components can be defined in several ways:
Locally – in the controller
Components only relevant to a particular controller are conventionally defined directly in a top-level JSDoc comment in the controller file.
Globally – in the generation script
Components that are reused across many endpoints can be defined in the generation script
cht-datasource type definitions
Endpoints that accept/return data defined by cht-datasource types can leverage schema components automatically created for these types. The $ref path for these components is #/components/schemas/${versionNamespace}.{typeName}. For example, the OpenAPI config for the GET /api/v1/person/{id} endpoint references the #/components/schemas/v1.Person schema which is automatically produced from the type information in the v1.Person interface. Changes to the v1.Person interface in cht-datasource will automatically be included in the OpenAPI configuration.
Note
The list of cht-datasource files containing types to include is currently hardcoded in the generation script. When a new data type is added to cht-datasource in a different file, the script must be updated to include that new file. (New types added to existing files will be automatically picked up without changes to the script.)
Deep linking to API docs
Deep links to specific endpoint operations on the REST API reference page follow a predictable format: /building/reference/api/#/${tag}/${operationId}. The tag and operationId values are determined by the OpenAPI configuration for the endpoint. For example, the GET /api/v1/person/{id} endpoint has tags: [Person] and operationId: v1PersonIdGet, so the deep link to that operation is /building/reference/api/#/Person/v1PersonIdGet.
Unfortunately, because the contents of the API reference page are generated at runtime, the internal link validation process cannot validate deep links to that page. Because of this, validation for links to that page has been disabled by setting the skipIncomingLinkValidation: true property in the front-matter.
Previewing changes locally
To render an in-progress openapi.json when running the cht-docs side locally, follow these steps:
- In cht-core, run
npm run build-documentationto regeneratecht-core/shared-libs/cht-datasource/docs/openapi.json. - Copy that file to
cht-docs/assets/openapi.json. - From the cht-docs root, start the dev server with
hugo server(ordocker compose up). - Open
/building/reference/api/in the browser — the page renders the local copy.
To revert to the published version, delete cht-docs/assets/openapi.json and restart the dev server.
Note
The cht-docs/assets/openapi.json file is for local preview only. Do not commit it — the production build references the spec published by cht-core.
Reference
- OpenAPI Specification 3.1.0 — the authoritative specification.
- OpenAPI Guide — a walkthrough of the available configuration options with examples.
Did this documentation help you ?