Sequelizeモデルから自動でSwagger型定義を生成する方法
はじめに
REST APIのドキュメント作成には、Swaggerが広く使用されています。この記事では、Sequelizeモデルから自動的にSwagger用の型定義を生成し、APIドキュメントを自動更新する方法を解説します。
プロジェクト構成例
.
└── backend/
└── src/
├── models/ # Sequelizeモデル
│ ├── index.ts
│ └── User.ts
├── scripts/
│ └── generateSwagger.ts # Swagger生成スクリプト
├── swagger-schemas.ts # 生成される型定義
└── server.ts # Express設定
実装手順
1. Sequelizeの定義からSwagger型定義を生成する関数の定義
src/scripts/generateSwagger.ts
import fs from 'fs';
import path from 'path';
import { Model, ModelStatic, DataTypes } from 'sequelize';
// Sequelizeの型をSwagger型に変換する関数
function getSwaggerType(sequelizeType: any): any {
const type = sequelizeType.toString().toLowerCase();
if (sequelizeType instanceof DataTypes.ENUM) {
return {
type: 'string',
enum: (sequelizeType as any).values,
};
}
if (type.includes('uuid')) {
return {
type: 'string',
format: 'uuid',
};
}
if (type.includes('int') || type.includes('float')) {
return { type: 'integer' };
}
if (type.includes('boolean')) {
return { type: 'boolean' };
}
if (type.includes('date')) {
return {
type: 'string',
format: 'date-time',
};
}
return { type: 'string' };
}
// モデルからSwaggerスキーマを生成
function generateSwaggerSchema(model: ModelStatic<Model>) {
const attributes = model.getAttributes();
const properties: Record<string, any> = {};
const required: string[] = [];
for (const [key, attribute] of Object.entries(attributes)) {
properties[key] = getSwaggerType(attribute.type);
if (!attribute.allowNull) {
required.push(key);
}
}
return {
type: 'object',
properties,
required: required.length > 0 ? required : undefined,
};
}
2. 共通レスポンススキーマの定義
Sequelizeの型定義とは関係ないが、よく使うレスポンスがあれば、定義する
src/scripts/generateSwagger.ts
const commonSchemas = {
SuccessResponse: {
type: 'object',
properties: {
message: {
type: 'string',
description: '処理成功時のメッセージ',
},
},
required: ['message'],
example: {
message: '正常に処理が完了しました',
},
},
Error400Response: {
type: 'object',
properties: {
error: {
type: 'string',
description: 'エラーメッセージ',
},
},
required: ['error'],
example: {
error: 'リクエストが不正です',
},
},
// ... その他のエラーレスポンス
};
3. スキーマ生成の実行
src/scripts/generateSwagger.ts
(async function () {
let output = `// This file is auto-generated. DO NOT EDIT.
export const swaggerSchemas = {
components: {
schemas: {
...${JSON.stringify(commonSchemas, null, 6)},`;
// モデルファイルを読み込んでスキーマを生成
fs.readdirSync(modelsDir)
.filter((file) => file.endsWith('.ts') && file !== 'index.ts')
.forEach((file) => {
const modelModule = require(path.join(modelsDir, file));
const model = modelModule.default;
if (model && model.prototype instanceof Model) {
const schema = generateSwaggerSchema(model);
output += `
${model.name}: ${JSON.stringify(schema, null, 6)},`;
}
});
output += `
}
}
};`;
fs.writeFileSync(outputPath, output);
console.log('✨ Swagger schemas generated successfully!');
})();
4. スキーマ出力の例
swagger-schemas.ts
// This file is auto-generated. DO NOT EDIT.
/* eslint-disable */
export const swaggerSchemas = {
components: {
schemas: {
...{
SuccessResponse: {
type: 'object',
properties: {
message: {
type: 'string',
description: '処理成功時のメッセージ',
},
},
required: ['message'],
example: {
message: '正常に処理が完了しました',
},
},
Error400Response: {
type: 'object',
properties: {
error: {
type: 'string',
description: 'エラーメッセージ',
},
},
required: ['error'],
example: {
error: 'リクエストが不正です',
},
},
},
User: {
type: 'object',
properties: {
id: {
type: 'string',
format: 'uuid',
},
username: {
type: 'string',
},
createdAt: {
type: 'string',
},
updatedAt: {
type: 'string',
},
},
required: ['id', 'username', 'createdAt', 'updatedAt'],
},
},
},
};
5. ExpressでのSchema利用例
Swaggerのoption設定で、先ほど作成したSchemaを反映させます
src/server.ts
import swaggerUi from 'swagger-ui-express';
import swaggerJsdoc from 'swagger-jsdoc';
import { swaggerSchemas } from './swagger-schemas';
// Swagger設定
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'API Documentation',
version: '1.0.0',
},
...swaggerSchemas,
},
apis: ['./src/routes/*.ts'],
};
const swaggerSpec = swaggerJsdoc(options);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
6. ルーターでの使用例
各プロパティを書くことなく、$refという形で型定義を記載することができます
src/routes/prototype.ts
/**
* @swagger
* /api/prototypes:
* post:
* summary: プロトタイプ作成
* requestBody:
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Prototype'
* responses:
* '201':
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Prototype'
* '400':
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Error400Response'
*/
router.post('/', async (req, res) => {
// 実装...
});
7. Swagger UI
レスポンス例にも適当な値が出力されるため、レスポンスの雰囲気を掴むには十分です
まとめ
Sequelizeモデルからの自動Swagger生成により:
- APIドキュメントの保守性向上
- モデル定義とAPI仕様の一貫性確保
- 開発効率の改善
が実現できます。