Documenting Express REST APIs with OpenAPI and JSDoc

As usual, this article isn’t meant as an in-depth guide, as much as a documentation of the what, why, and how of certain architectural choices. If you’re trying to achieve the same thing and need help, leave a comment!

Goals & Constrain…

As usual, this article isn’t meant as an in-depth guide, as much as a documentation of the what, why, and how of certain architectural choices. If you’re trying to achieve the same thing and need help, leave a comment!



Goals & Constraints

  • To document BobaBoard‘s REST API.
  • Standardize (and document) both the parameters and the return values of various endpoints.
  • The documentation should be as close as possible to the source code it describes.
  • The documentation should be served through a docusaurus instance hosted on a different server.



Final Result



Architecture

How everything interacts



Documentation

The BobaBoard Rest API Documentation



How To



Packages used

  • SwaggerJSDoc: to turn JSDocs into the final OpenAPI spec (served at /open-api.json).
  • Redocusaurus: to embed Redoc into Docusaurus. There are other options for documentation, like any OpenAPI/Swagger compatible tool (e.g. SwaggerUI), but Redoc is the nicest feeling one.



Configuration (Express)



OpenAPI Options

const options = {
  definition: {
    openapi: "3.1.0",
    info: {
      title: "BobaBoard's API documentation.",
      version: "0.0.1",
      // Note: indenting the description will cause the markdown not to format correctly.
      description: `
# Intro
Welcome to the BobaBoard's backend API. This is still a WIP.

# Example Section
This is just to test that sections work. It will be written better later.
        `,
      contact: {
        name: "Ms. Boba",
        url: "https://www.bobaboard.com",
        email: "ms.boba@bobaboard.com",
      },
    },
    servers: [
      {
        url: "http://localhost:4200/",
        description: "Development server",
      },
    ],
    // These are used to group endpoints in the sidebar
    tags: [
      {
        name: "/posts/",
        description: "All APIs related to the /posts/ endpoints.",
      },
      {
        name: "/boards/",
        description: "All APIs related to the /boards/ endpoints.",
      },
      {
        name: "todo",
        description: "APIs whose documentation still needs work.",
      },
    ],
    // Special Redoc section to control how tags display in the sidebar.
    "x-tagGroups": [
      {
        name: "general",
        tags: ["/posts/", "/boards/"],
      },
    ],
  },
  // Which paths to parse the API specs from.
  apis: ["./types/open-api/*.yaml", "./server/*/routes.ts"],
};



Open API endpoint

import swaggerJsdoc from "swagger-jsdoc";

const specs = swaggerJsdoc(options);
app.get("/open-api.json", (req, res) => {
  res.setHeader("Content-Type", "application/json");
  res.send(specs);
});



Type Spec

/types/open-api/contribution.yaml

# Note the /components/schemas/[component name] hierarchy.
# This is used to refer to these types in the endpoint
# documentation.
components:
  schemas:
    Contribution:
      type: object
      properties:
        post_id:
          type: string
          format: uuid
        parent_thread_id:
          type: string
          format: uuid
        parent_post_id:
          type: string
          format: uuid
        secret_identity:
          $ref: "#/components/schemas/Identity"
      required:
        - post_id
        - parent_thread_id
        - secret_identity



Endpoint Documentation

This should be repeated for every API endpoint you wish to document.

/**
 * @openapi
 * posts/{postId}/contribute:
 *   post:
 *     summary: Replies to a contribution
 *     description: Posts a contribution replying to the one with id {postId}.
 *     tags:
 *       - /posts/
 *       - todo
 *     parameters:
 *       - name: postId
 *         in: path
 *         description: The uuid of the contribution to reply to.
 *         required: true
 *         schema:
 *           type: string
 *           format: uuid
 *     responses:
 *       403:
 *         description: User is not authorized to perform the action.
 *       200:
 *         description: The contribution was successfully created.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 contribution:
 *                   $ref: "#/components/schemas/Contribution"
 *                   description: Finalized details of the contributions just posted.
 */
router.post("/:postId/contribute", isLoggedIn, async (req, res) => {
  // The endpoint code
}



Configuration (Docusaurus)

docusaurus.config.js:

module.exports = {
  // other config stuff
  // ...
  presets: [
    // other presets,
    [
      "redocusaurus",
      {
        specs: [
          {
            routePath: "docs/engineering/rest-api/",
            // process.env.API_SPEC is used to serve from localhost during development
            specUrl:
              process.env.API_SPEC ||
              "[prod_server_url]/open-api.json",
          },
        ],
        theme: {
          // See options at https://github.com/Redocly/redoc#redoc-options-object
          redocOptions: {
            expandSingleSchemaField: true,
            expandResponses: "200",
            pathInMiddlePanel: true,
            requiredPropsFirst: true,
            hideHostname: true,
          },
        },
      },
    ],
  ],
}

Print Share Comment Cite Upload Translate
APA
Essential Randomness | Sciencx (2024-03-29T04:45:55+00:00) » Documenting Express REST APIs with OpenAPI and JSDoc. Retrieved from https://www.scien.cx/2021/07/18/documenting-express-rest-apis-with-openapi-and-jsdoc/.
MLA
" » Documenting Express REST APIs with OpenAPI and JSDoc." Essential Randomness | Sciencx - Sunday July 18, 2021, https://www.scien.cx/2021/07/18/documenting-express-rest-apis-with-openapi-and-jsdoc/
HARVARD
Essential Randomness | Sciencx Sunday July 18, 2021 » Documenting Express REST APIs with OpenAPI and JSDoc., viewed 2024-03-29T04:45:55+00:00,<https://www.scien.cx/2021/07/18/documenting-express-rest-apis-with-openapi-and-jsdoc/>
VANCOUVER
Essential Randomness | Sciencx - » Documenting Express REST APIs with OpenAPI and JSDoc. [Internet]. [Accessed 2024-03-29T04:45:55+00:00]. Available from: https://www.scien.cx/2021/07/18/documenting-express-rest-apis-with-openapi-and-jsdoc/
CHICAGO
" » Documenting Express REST APIs with OpenAPI and JSDoc." Essential Randomness | Sciencx - Accessed 2024-03-29T04:45:55+00:00. https://www.scien.cx/2021/07/18/documenting-express-rest-apis-with-openapi-and-jsdoc/
IEEE
" » Documenting Express REST APIs with OpenAPI and JSDoc." Essential Randomness | Sciencx [Online]. Available: https://www.scien.cx/2021/07/18/documenting-express-rest-apis-with-openapi-and-jsdoc/. [Accessed: 2024-03-29T04:45:55+00:00]
rf:citation
» Documenting Express REST APIs with OpenAPI and JSDoc | Essential Randomness | Sciencx | https://www.scien.cx/2021/07/18/documenting-express-rest-apis-with-openapi-and-jsdoc/ | 2024-03-29T04:45:55+00:00
https://github.com/addpipe/simple-recorderjs-demo