Open6

openapiのexamplesの値をmockとして取り出したい

Cookie_ggCookie_gg

何がしたいのか

openapiから取得できるjsonファイルやymlファイルに記述されているexamplesの値を、型指定された状態でmockとして取り出し、tsファイル出力をしたい。

Cookie_ggCookie_gg

そのmockをmswで使うなら。。。って人向けのツール見つけた。
examplesの値を各エンドポイント、各メソッドに対してのレスポンスとして扱い、自動でハンドラーを生成してくれるらしい。

https://github.com/kazuyaseki/openapi-to-msw

Cookie_ggCookie_gg

openapiでのexampleがスキーマ通りという前提で、mock自動生成ツールを作ることはダメとして、バックエンドでexample定義時にスキーマの型の値のみ受け取れるようにするのがbetterかも。

主はバックエンドの構成がnestjs+zod-openapi+@nestjs/swaggerだからexampleを定義するextendApiを拡張する。

~/libs/zod
import type { SchemaObject as SchemaObjectOrigin } from 'openapi3-ts';
import { z } from 'zod';

type SchemaObject<T> = Omit<SchemaObjectOrigin, "example", "examples"> & {
  example?: T;
  examples?: T[];
};

export const extendApiWithExample = <T extends OpenApiZodAny>(schema: T) => {
  return (schemaObject: SchemaObject<z.infer<typeof schema>>) => extendApi(schema, schemaObject);
};
Cookie_ggCookie_gg

実際にスキーマを定義してみる。
今回はzod-mockを利用して、mockを自動生成し、それをexampleとして定義する。

~/schema/User
import { z } from 'zod';
import { generateMock } from '@anatine/zod-mock';
import { extendApi } from '@anatine/zod-openapi';
import { createZodDto } from '@anatine/zod-nestjs';

import { extendApiWithExample } from '~/libs/zod';

const zUser = z.object({
  id: extendApi(z.string(), {
    type: 'string',
    uniqueItems: true,
  }),
  name: extendApi(z.string(), {
    type: 'string',
  }),
  email: extendApi(z.string().email(), {
    type: 'string',
    uniqueItems: true,
  }),
});

export class User extends createZodDto(
  extendApiWithExample(zUser)({
    title: 'User',
    example: generateMock(zUser),
    examples: generateMock(zUser.array().length(3)),
  }),
) {}
Cookie_ggCookie_gg

しっかりとexampleとして認識されていることがわかる。

api.json
{
  ...,
  "components": {
    "schemas": {
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "uniqueItems": true
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email",
            "uniqueItems": true
          }
        },
        "required": [
          "id",
          "name",
          "email"
        ],
        "title": "User",
        "example": {
          "id": "odit",
          "name": "Marion Streich",
          "email": "Solon.Rice@example.com"
        },
        "examples": [
          {
            "id": "voluptatibus",
            "name": "Miss Blanche Cummings",
            "email": "Maverick_Bailey98@example.org"
          },
          {
            "id": "amet",
            "name": "Leroy Spencer",
            "email": "Kavon.Gutkowski36@example.com"
          },
          {
            "id": "repudiandae",
            "name": "Tyler Anderson",
            "email": "Kailyn.Gusikowski@example.org"
          }
        ]
      }
    }
  }
  ...,
}