Mobile Factory Tech Blog

技術好きな方へ!モバイルファクトリーのエンジニアたちが楽しい技術話をお届けします!

nestjs/swaggerで生成したOpenAPI 3.0の定義ファイルを使ってReDocにWebhookの項目を表示させる

みなさんこんにちはエンジニアのEadaedaです。

皆さんのチームではAPIドキュメントの生成に何をお使いですか?UniqysチームではReDocを使っています。 nestjs/swaggerを使ってコントローラーから生成したOpenAPIの定義ファイルを与えるだけでリッチなドキュメントを作ってくれるのでいい感じです。

github.com

プロダクトの開発をすすめるうちに、Webhookに関するドキュメントも必要になりました。しかし、nestjs/swagger (2022/05/25時点のlatestである v5.2.1)では、Webhookのドキュメント生成に標準対応していませんでした。この記事ではこの問題に対処する方法の一つを紹介したいと思います。

前置き

OpenAPI 3.1で webhooks フィールドを用いてWebhookのドキュメントを生成する

OpenAPI 3.1からは webhooks というフィールドが追加になったので、これを使ってReDocにドキュメントを生成させることができます。例えば以下のような定義ファイルだとして

{
  "openapi": "3.1.0",
  "info": {
    "title": "とてもすごいAPI",
    "description": "すごいAPIのドキュメントだよ",
    "version": "1.0"
  },
  "components": {
    "schemas": {
      "Model": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "API太郎",
            "description": "あなたの名前だよ"
          },
          "age": {
            "type": "number",
            "example": "3000",
            "description": "あなたの年齢だよ"
          }
        }
      }
    }
  },
  "webhooks": {
    "sugoi-webhook": {
      "post": {
        "summary": "すごいWebhook",
        "operationId": "sugoi-webhook",
        "tags": ["Webhook"],
        "description": "すごいWebhookを送信するよ",
        "requestBody": {
          "description": "Webhookにより送信されるデータだよ",
          "content": {
            "application/json; charset=utf-8": {
              "schema": {
                "$ref": "#/components/schemas/Model"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    }
  }
}

以下のようなドキュメントが生成されます。

とてもいい感じですね。これを使ってドキュメント更に充実させていきたいところですが、先にも述べたように、nestjs/swaggerでは webhooksを含むような定義ファイルを生成できません。さらに言うとOpenAPI 3.0な定義ファイルを生成するので、webhooksフィールドも使えませんでした。

OpenAPI 3.0 で x-webhooks フィールドを用いて、Webhookのドキュメントを生成する

なにか解決策は無いかと色々探していたところ、ReDocのドキュメントに x-webhooks というものを発見しました。

redocly.com

x-webhooksフィールドをOpenAPIのルートに記述することで、OpenAPI 3.1のwebhooksで生成されるドキュメントをOpenAPI 2.0/3.0でも生成できるようです。試してみましょう。

{
  "openapi": "3.0.0",
  "info": { ... },
  "components": { ... },

  "x-webhooks": {
    "sugoi-webhook": {
      "post": {
        "summary": "すごいWebhook",
        "operationId": "sugoi-webhook",
        "tags": ["Webhook"],
        "description": "すごいWebhookを送信するよ。OpenAPI 3.0だけど`x-webhooks`を使って書いているよ",
        "requestBody": {
          "description": "Webhookにより送信されるデータだよ",
          "content": {
            "application/json; charset=utf-8": {
              "schema": {
                "$ref": "#/components/schemas/Model"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    }
  }
}

良さそうですね。

本題

swaggerの定義ファイル生成時に x-webhooks を差し込み、Webhookのドキュメントを生成する

OpenAPI 3.0な定義ファイルを生成するnestjs/swaggerでは、x-webhooksを使えば良いことはわかりました。ただ、定義ファイル生成のたびに手で追記するのは大変なのでどうにか自動で行いたいです。いくつか方法はあると思うのですが、ここではTypeScriptで生成したドキュメントオブジェクトに直接挿入する方法で行いたいと思います。

import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";
import { INestApplication } from "@nestjs/common";

export function build(app: INestApplication) {
  const options = new DocumentBuilder()
    .setTitle("とてもすごいAPI")
    .setVersion("1.0")
    .setDescription("すごいAPIのドキュメントだよ");

  const document = SwaggerModule.createDocument(app, options);

  (document as any)["x-webhooks"] = {
    "sugoi-webhook": {
      post: {
        summary: "すごいWebhook",
        operationId: "sugoi-webhook",
        tags: ["Webhook"],
        description: "すごいWebhookを送信するよ。OpenAPI 3.0だけど`x-webhooks`を使って書いているよ",
        requestBody: {
          description: "Webhookにより送信されるデータだよ",
          content: {
            "application/json; charset=utf-8": {
              schema: {
                $ref: "#/components/schemas/Model"
              }
            }
          }
        },
        responses: {
          200: {
            description: "",
          },
        },
      },
    },
  };

  return document;
}

特に工夫もないですが…。後はこの関数が返してきたオブジェクトをファイルに書き出すだけですね。

まとめ

  • OpenAPI 3.1からは webhooks フィールドを定義すると、ReDocでWebhookのドキュメントが生成されるようになる
  • OpenAPI 3.0では x-webhooks フィールドを代わりに定義することで、同様にReDocでWebhookのドキュメントが生成されるようになる
  • しかし、nestjs/swagger(v5.2.1)では、webhooksx-webhooksに標準対応していない
  • そこで、x-webhooksを直接差し込むコードを記述し、定義ファイルの生成時に実行することで自動生成をするようにした

ちなみに、この対応は以下のIssueが解決するまでの対応となります。

github.com

以上です。