Swagger EditorのGenerate Server (nodejs-server)で提供されるSwagger UIやSpecのPathを変更する


Swagger Editorでは、生成されたドキュメントをホストするサーバ環境を「Generate Server」で生成することができますが、nodejs-serverを選択した際のSwagger UIやSpecのホストされるPathを変更する方法をメモしておきます。

## やりたいこと

デフォルトでは以下のindex.jsファイルが生成され、これを実行するとSwagger UIおよびSwagger Specが以下のURLにマップされます。

* http://localhost:8080/docs （Swagger UIのURL）
* http://localhost:8080/api-docs （APIのSwagger SpecのURL）

これを、

* http://localhost:8080/hoge/foo/docs
* http://localhost:8080/hoge/foo/api-docs

などに変更したい。

>docsやapi-docsとする必要はなく、任意でもOK。


## 標準出力されているコード

いろいろな処理がされているようですが、これには[swagger-tools](https://github.com/apigee-127/swagger-tools)というモジュールが中核となっているようです。

標準で出力されるコードは以下の通り。ほとんど隠蔽されています。

```js:index.js
'use strict';

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

var app = require('connect')();
var swaggerTools = require('swagger-tools');
var jsyaml = require('js-yaml');
var serverPort = 8080;

// swaggerRouter configuration
var options = {
  swaggerUi: path.join(__dirname, '/swagger.json'),
  controllers: path.join(__dirname, './controllers'),
  useStubs: process.env.NODE_ENV === 'development' // Conditionally turn on stubs (mock mode)
};

// The Swagger document (require it, build it programmatically, fetch it from a URL, ...)
var spec = fs.readFileSync(path.join(__dirname,'api/swagger.yaml'), 'utf8');
var swaggerDoc = jsyaml.safeLoad(spec);

// Initialize the Swagger middleware
swaggerTools.initializeMiddleware(swaggerDoc, function (middleware) {

  // Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain
  app.use(middleware.swaggerMetadata());

  // Validate Swagger requests
  app.use(middleware.swaggerValidator());

  // Route validated requests to appropriate controller
  app.use(middleware.swaggerRouter(options));

  // Serve the Swagger documents and Swagger UI
  app.use(middleware.swaggerUi());

  // Start the server
  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);
  });

});
```

## 変更すべき箇所

Swagger UIのURLはswaggerUI:オプションで、SpecのURLはapiDocs:オプションで設定し、app.use(middleware.swaggerUi(options4ui))という形でミドルウエアに渡してやります。

>URL変更なのでswaggerRouterのオプションを変更するものだと思い込み、しばらくハマりました。

```diff:index.js
'use strict';

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

var app = require('connect')();
var swaggerTools = require('swagger-tools');
var jsyaml = require('js-yaml');
var serverPort = 8080;

// swaggerRouter configuration
var options = {
  swaggerUi: path.join(__dirname, '/swagger.json'),
  controllers: path.join(__dirname, './controllers'),
  useStubs: process.env.NODE_ENV === 'development' // Conditionally turn on stubs (mock mode)
};

+var options4ui = {
+	swaggerUi: "/hoge/foo/docs",
+	apiDocs: "/hoge/foo/api-docs"
+}

// The Swagger document (require it, build it programmatically, fetch it from a URL, ...)
var spec = fs.readFileSync(path.join(__dirname,'api/swagger.yaml'), 'utf8');
var swaggerDoc = jsyaml.safeLoad(spec);

// Initialize the Swagger middleware
swaggerTools.initializeMiddleware(swaggerDoc, function (middleware) {

  // Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain
  app.use(middleware.swaggerMetadata());

  // Validate Swagger requests
  app.use(middleware.swaggerValidator());

  // Route validated requests to appropriate controller
  app.use(middleware.swaggerRouter(options));

  // Serve the Swagger documents and Swagger UI
+ app.use(middleware.swaggerUi(options4ui));

  // Start the server
  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);
  });

});
```

Pathが変更されても、最後のconsole.log()は静的にPathがコードされているため、変更されません。気になる人は変更しましょう。

## その他備忘

### chromeがなぜかSpecのURLをキャッシュ

本番サーバに展開した際、Swagger UIのURL変更は素直に反映されるものの、SpecのURLはキャッシュされ反映されませんでした。command + shift + Rで閲覧する必要があります。

### Basic認証をかけるとエラー（バッヂ）

どうやら外部サイトでSpecの内容の検証をしているようなのですが、Basic認証をかけると連携できず、エラーメッセージが出ます。
なお、このバリデーション機能はlocalhostでは機能せず、IPの際に機能するようです（ローカルアドレスでも表示されます）。

これを消すには、直接ファイルをいじるしかなさそうです。

node_modules/swagger-tools/middleware/swagger-ui/index.htmlの70行目付近にvalidatorUrl: nullを挿入します。
以下抜粋。

```diff
          docExpansion: "none",
          jsonEditor: false,
          apisSorter: "alpha",
          defaultModelRendering: 'schema',
          showRequestHeaders: false,
+          validatorUrl: null
        });
```