Swagger EditorのGenerate Serverで生成したNode.js serverのcors問題を解消した話


備忘録代わりとして書きます。
間違い、より楽なやり方もあると思いますのでご指摘大歓迎です。

概要

openapi3.0でYAMLファイルを書き、
Swagger EditorのGenerate Server機能を用いてNode.jsを自動生成し、
HerokuへデプロイしてMock Serverにしようとしました。

やり方

Mock Serverコードを記述したらGenerate Server > nodejs-serverを選択し、サーバコードをダウンロードする。

ダウンロードしたNode.jsを解凍し、index.jsを変更する。

./index.js

'use strict';

var path = require('path');
var http = require('http');

var oas3Tools = require('oas3-tools');
//var serverPort = 8080;//ここを変更
var serverPort = process.env.PORT || 8080;

// swaggerRouter configuration
var options = {
    routing: {
        controllers: path.join(__dirname, './controllers')
    },
};

var expressAppConfig = oas3Tools.expressAppConfig(path.join(__dirname, 'api/openapi.yaml'), options);
var app = expressAppConfig.getApp();

// Initialize the Swagger middleware
http.createServer(app).listen(serverPort, function () {
    console.log('Your server is listening on port %d (http://localhost:%d)', serverPort, serverPort);
    console.log('Swagger-ui is available on http://localhost:%d/docs', serverPort);
});

発生した問題

Herokuへデプロイし、確認した所

Access to XMLHttpRequest at 'http://localhost:8081' from origin 'https://test-app-20210113.herokuapp.com/
' has been blocked by CORS policy:

のようなエラーが発生。
調べてみたところ、CORS policyというものが問題のよう。

cors modulesをインポートしてexpress moduleを使う際に
app.(use(cors))とすると解決できるようですが、そもそもexpress moduleはどこ・・・

解決法

index.jsを読んでみるとoas3Toolsという独自モジュールを使っているらしい。
node_modules -> oas3-tools -> dist -> middleware ->express.app.config.jsにcorsをインポート

./node_modules/oas3-tools/dist/middleware/express.app.config.js

'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExpressAppConfig = void 0;
const express = require("express");
const cors = require("cors");//追加
const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser");
const swagger_ui_1 = require("./swagger.ui");
const swagger_router_1 = require("./swagger.router");
const swagger_parameters_1 = require("./swagger.parameters");
const logger = require("morgan");
const fs = require("fs");
const jsyaml = require("js-yaml");
const OpenApiValidator = require("express-openapi-validator");
class ExpressAppConfig {
    constructor(definitionPath, appOptions) {
        this.definitionPath = definitionPath;
        this.routingOptions = appOptions.routing;
        this.setOpenApiValidatorOptions(definitionPath, appOptions);
        this.app = express();
        const spec = fs.readFileSync(definitionPath, 'utf8');
        const swaggerDoc = jsyaml.safeLoad(spec);
        this.app.use(cors());//追加
        this.app.use(bodyParser.urlencoded());
        this.app.use(bodyParser.text());
        this.app.use(bodyParser.json());
        this.app.use(this.configureLogger(appOptions.logging));
        this.app.use(express.json());
        this.app.use(express.urlencoded({ extended: false }));
        this.app.use(cookieParser());
        const swaggerUi = new swagger_ui_1.SwaggerUI(swaggerDoc, appOptions.swaggerUI);
        this.app.use(swaggerUi.serveStaticContent());
        this.app.use(OpenApiValidator.middleware(this.openApiValidatorOptions));
        this.app.use(new swagger_parameters_1.SwaggerParameters().checkParameters());
        this.app.use(new swagger_router_1.SwaggerRouter().initialize(this.routingOptions));
        this.app.use(this.errorHandler);
    }

gitignoreからnode_modulesを削除し、この状態でHerokuへデプロイした所きちんと動くようになりました。

patch-packageの利用

直すことは出来ましたが、node_modulesを直接いじり、
node_modulesごとHerokuへデプロイするのは色々な面で問題がある実装なので
patch-package moduleをインポートして利用することに
(node_moduleを手動で変更している時点で本来良くないですが・・・)
詳しくは参考文献をご覧ください。

参考文献

なんとなく CORS がわかる...はもう終わりにする。
Swagger x Heroku で手軽に API モック&ドキュメントを作る
かゆいところに手が届く!patch-packageでnpmパッケージを乗りこなそう