Open6
openapiのexamplesの値をmockとして取り出したい
何がしたいのか
openapiから取得できるjsonファイルやymlファイルに記述されているexamplesの値を、型指定された状態でmockとして取り出し、tsファイル出力をしたい。
openapi2aspidaやopenapi-typescriptなど、型生成をしてくれるライブラリはいくつかあるが、examplesの値を出力してくれる機能が実装されているライブラリは見当たらない。
openapi2aspidaに関しては似たようなことをしたい人がいた。しかしexamplesはtypescriptでいうany型で、なんでもあり状態で型安全に値を扱えない。
そのmockをmswで使うなら。。。って人向けのツール見つけた。
examplesの値を各エンドポイント、各メソッドに対してのレスポンスとして扱い、自動でハンドラーを生成してくれるらしい。
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);
};
実際にスキーマを定義してみる。
今回は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)),
}),
) {}
しっかりと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"
}
]
}
}
}
...,
}