Repository: lukeautry/tsoa (ts)

Issue:
Swagger -> OpenAPI (v2)
The name swagger is outdated for about 4 years now, version 3 of tsoa gives us the unique opportunity to catch up. All references to swagger should be updated.

Todo:
- [x] Update Docs
- [x] Update API
- [ ] Update internals (can be done after 3.0)

## Breaking change?
Yes!

If anyone is interested in updating the docs, I'll gladly accept a PR. Please make sure you target the `3.x` branch on github.

Pull request:
Swagger -> OpenAPI
### All Submissions:

* [x] Have you followed the guidelines in our [Contributing](https://github.com/lukeautry/tsoa/tree/master/docs/CONTRIBUTING.md) document?
* [x] Have you checked to ensure there aren't other open [Pull Requests](https://github.com/lukeautry/tsoa/pulls) for the same update/change?
* [ ] Have you written unit tests?
* [ ] Have you written unit tests that cover the negative cases (i.e.: if bad data is submitted, does the library respond properly)?
* [x] This PR is associated with an existing issue?

Closes #634 

### If this is a new feature submission:

* [x] Has the issue had a maintainer respond to the issue and clarify that the feature is something that aligns with the [goals](https://github.com/lukeautry/tsoa#goal) and [philosophy](https://github.com/lukeautry/tsoa#philosophy) of the project?

**Breaking Changes:**
```diff
Calling the tsoa command
- tsoa swagger
+ tsoa spec

- tsoa swagger-and-routes
+ tsoa spec-and-routes

Manually calling spec generation
- await generateSwaggerSpec(swaggerConfig, routesConfig, compilerOptions, config.ignore);
+ await generateSpec(openapiConfig, compilerOptions, config.ignore);
```

tsoa.json:

```
{
  "swagger": {},
  "routes: {},
  "entryFile": ""
}
```
becomes
```
{
  "spec": {},
  "routes: {},
  "entryFile": ""
}
```


Patch:
diff --git a/README.MD b/README.MD
index 52f565ee..5c391ce9 100644
--- a/README.MD
+++ b/README.MD
@@ -16,7 +16,7 @@ Pronounced so·uh
       + [Using CLI](#using-cli)
       + [Programmatic](#programmatic)
       + [Automating Regeneration](#automating-regeneration)
-    - [Can I use OpenAPI 3.0 instead of Swagger v2?](#can-i-use-openapi-30-instead-of-swagger-v2)
+    - [Can I use OpenAPI 3.0 instead of OpenAPI 2 (formerly Swagger)?](#can-i-use-openapi-3-instead-of-openapi-2-(formerly-swagger))
     - [How to ensure no additional properties come in at runtime](#how-to-ensure-no-additional-properties-come-in-at-runtime)
     - [Dealing with duplicate model names](#dealing-with-duplicate-model-names)
     - [Overriding route template](#overriding-route-template)
@@ -25,18 +25,18 @@ Pronounced so·uh
     - [Dependency injection or IOC](#dependency-injection-or-ioc)
       + [InversifyJS](#inversifyjs)
       + [typescript-ioc](#typescript-ioc)
-    - [Specify error response types for Swagger](#specify-error-response-types-for-swagger)
+    - [Specify error response types for OpenAPI](#specify-error-response-types-for-openapi)
     - [Authentication](#authentication)
     - [Path mapping](#path-mapping)
     - [Uploading files](#uploading-files)
-    - [Using awesome Swagger tools](#using-awesome-swagger-tools)
+    - [Using awesome OpenAPI tools](#using-awesome-openapi-tools)
   * [Decorators](#decorators)
     - [Security](#security)
     - [Tags](#tags)
     - [OperationId](#operationid)
     - [Deprecated](#deprecated)
   * [Command Line Interface](#command-line-interface)
-    - [Swagger spec generation](#swagger-spec-generation)
+    - [OpenAPI spec generation](#spec-generation)
     - [Route generation](#route-generation)
   * [Examples](#examples)
   * [Help wanted](#help-wanted)
@@ -44,10 +44,10 @@ Pronounced so·uh
 ## Goal
 
 - TypeScript controllers and models as the single source of truth for your API
-- A valid swagger spec (or OpenAPI 3.0 if you choose 😍) is generated from your controllers and models, including:
+- A valid OpenAPI (formerly Swagger) spec (2.0 or 3.0 if you choose 😍) is generated from your controllers and models, including:
     - Paths (e.g. GET /Users)
     - Definitions based on TypeScript interfaces (models)
-    - Parameters/model properties marked as required or optional based on TypeScript (e.g. myProperty?: string is optional in the Swagger spec)
+    - Parameters/model properties marked as required or optional based on TypeScript (e.g. myProperty?: string is optional in the OpenAPI spec)
     - jsDoc supported for object descriptions (most other metadata can be inferred from TypeScript types)
 - Routes are generated for middleware of choice
     - Express, Hapi, and Koa currently supported, other middleware can be supported using a simple handlebars template
@@ -60,8 +60,8 @@ Pronounced so·uh
 - Use jsdoc for pure text metadata (e.g. endpoint descriptions)
 - Minimize boilerplate
 - Models are best represented by interfaces (pure data structures), but can also be represented by classes
-- Runtime validation of tsoa should behave as closely as possible to the specifications that the generated Swagger/OpenAPI schema describes. Any differences in validation logic are clarified by logging warnings during the generation of the swagger document and/or the routes.
-    - Please note that by [enabling OpenAPI 3+](#can-i-use-openapi-30-instead-of-swagger-v2) you minimize the chances of divergent validation logic since OpenAPI has a more expressive schema syntax.
+- Runtime validation of tsoa should behave as closely as possible to the specifications that the generated OpenAPI 2/3 schema describes. Any differences in validation logic are clarified by logging warnings during the generation of the OpenAPI Specification (OAS) and/or the routes.
+    - Please note that by enabling OpenAPI 3 you minimize the chances of divergent validation logic since OpenAPI 3 has a more expressive schema syntax.
 
 ## How it works
 
@@ -103,7 +103,7 @@ export class UsersController extends Controller {
   }
 }
 ```
-Note: tsoa can not create swagger documents from interfaces that are defined in external dependencies. This is by design. Full explanation available in [ExternalInterfacesExplanation.MD](https://github.com/lukeautry/tsoa/blob/master/docs/ExternalInterfacesExplanation.MD)
+Note: tsoa can not create OpenAPI 2 (formerly Swagger) documents from interfaces that are defined in external dependencies. This is by design. Full explanation available in [ExternalInterfacesExplanation.MD](https://github.com/lukeautry/tsoa/blob/master/docs/ExternalInterfacesExplanation.MD)
 
 ### Create Models
 ```typescript
@@ -137,8 +137,8 @@ Note that type aliases are only supported for string literal types like `type st
 
 #### Using CLI
 ```typescript
-// generate swagger.json
-tsoa swagger
+// generate OAS
+tsoa spec
 
 // generate routes
 tsoa routes
@@ -149,10 +149,10 @@ See [CLI documentation](#command-line-interface)
 #### Programmatic
 
 ```typescript
-import { generateRoutes, generateSwaggerSpec, RoutesConfig, SwaggerConfig } from 'tsoa';
+import { generateRoutes, generateSpec, ExtendedRoutesConfig, ExtendedSpecConfig } from 'tsoa';
 
 (async () => {
-  const swaggerOptions: SwaggerConfig = {
+  const specOptions: ExtendedSpecConfig = {
     basePath: '/api',
     entryFile: './api/server.ts',
     specVersion: 3,
@@ -160,15 +160,15 @@ import { generateRoutes, generateSwaggerSpec, RoutesConfig, SwaggerConfig } from
     controllerPathGlobs: ['./routeControllers/**/*Controller.ts'],
   };
 
-  const routeOptions: RoutesConfig = {
+  const routeOptions: ExtendedRoutesConfig = {
     basePath: '/api',
     entryFile: './api/server.ts',
     routesDir: './api',
   };
 
-  await generateSwaggerSpec(swaggerOptions, routeOptions);
+  await generateSpec(specOptions);
 
-  await generateRoutes(routeOptions, swaggerOptions);
+  await generateRoutes(routeOptions);
 })();
 ```
 
@@ -180,13 +180,13 @@ You might find it convenient to automatically generate again. To do this, add a
 ```json
   "scripts": {
     // ... other stuff (note that comments are not valid JSON, so please remove this)
-    "tsoa:gen": "yarn tsoa swagger -c ./api/tsoa.json && yarn tsoa routes -c ./api/tsoa.json"
+    "tsoa:gen": "yarn tsoa spec -c ./api/tsoa.json && yarn tsoa routes -c ./api/tsoa.json"
   },
 ```
 
 Then when you've made a change to an API, you simply run "yarn tsoa:gen"
 
-Note: You can also integrate the swagger regeneration directly into your build step, but there are risks. To do that, ADDITIONAL add it to your build script in package.json:
+Note: You can also integrate the OpenAPI 2 (formerly Swagger) regeneration directly into your build step, but there are risks. To do that, ADDITIONAL add it to your build script in package.json:
 ```json
   "scripts": {
     // ... other stuff (note that comments are not valid JSON, so please remove this)
@@ -194,13 +194,13 @@ Note: You can also integrate the swagger regeneration directly into your build s
   },
 ```
 
-### Can I use OpenAPI 3.0 instead of Swagger v2?
+### Can I use OpenAPI 3 instead of OpenAPI 2 (formerly Swagger)?
 
-Yes, set `swagger.specVersion` to `3` in your `tsoa.json` file. See more config options by looking at [the config type definition](https://github.com/lukeautry/tsoa/blob/master/src/config.ts).
+Yes, set `spec.specVersion` to `3` in your `tsoa.json` file. See more config options by looking at [the config type definition](https://github.com/lukeautry/tsoa/blob/master/src/config.ts).
 
 ### How to ensure no additional properties come in at runtime
 
-By default, Swagger allows for models to have [`additionalProperties`](https://swagger.io/docs/specification/data-models/dictionaries/). If you would like to ensure at runtime that the data has only the properties defined in your models, set the `noImplicitAdditionalProperties` [config](https://github.com/lukeautry/tsoa/blob/master/src/config.ts) option to either `"silently-remove-extras"` or `"throw-on-extras"`.
+By default, OpenAPI allows for models to have [`additionalProperties`](https://swagger.io/docs/specification/data-models/dictionaries/). If you would like to ensure at runtime that the data has only the properties defined in your models, set the `noImplicitAdditionalProperties` [config](https://github.com/lukeautry/tsoa/blob/master/src/config.ts) option to either `"silently-remove-extras"` or `"throw-on-extras"`.
 
 Caveats:
   * The following types will always allow additional properties due to the nature of the way they work:
@@ -237,7 +237,7 @@ Route templates are generated from predefined handlebar templates. You can overr
 by defining it in your tsoa.json configuration. Route paths are generated based on the middleware type you have defined.
 ```json
 {
-  "swagger": {
+  "spec": {
     ...
   },
   "routes": {
@@ -255,10 +255,10 @@ by defining it in your tsoa.json configuration. Route paths are generated based
 You have two options for how to tell tsoa where it can find the controllers that it will use to create the auto-generated `routes.ts` file.
 
 #### (1) Using automatic controllers discovery
-You can tell `tsoa` to use your automatic controllers discovery by providing a [minimatch glob](http://www.globtester.com/) in the [config](https://github.com/lukeautry/tsoa/blob/master/src/config.ts) file (e.g. `tsoa.json`). It can be provided on `config.swagger` or `config.routes`.
+You can tell `tsoa` to use your automatic controllers discovery by providing a [minimatch glob](http://www.globtester.com/) in the [config](https://github.com/lukeautry/tsoa/blob/master/src/config.ts) file (e.g. `tsoa.json`). It can be provided on `config.spec` or `config.routes`.
 
 Pros:
-  * New developers can add a controller without having to know how tsoa "crawls" for the controllers. As long as their controller is caught by the glob that you provide, the controller will be added to the swagger documentation and to the auto-generated `routes.ts` file.
+  * New developers can add a controller without having to know how tsoa "crawls" for the controllers. As long as their controller is caught by the glob that you provide, the controller will be added to the OpenAPI documentation and to the auto-generated `routes.ts` file.
   
 Cons:
   * It could be potentially slower (but not significantly slow) than the alternative option described further down in the readme.
@@ -286,7 +286,7 @@ Pros:
   * The tsoa route generation will be faster.
   
 Cons:
-  * New developers on your team might add a controller and not understand why the new controller was not exposed to the router or to the swagger generation. If this is a problem for you, please us the automatic controller discovery option described above.
+  * New developers on your team might add a controller and not understand why the new controller was not exposed to the router or to the OpenAPI generation. If this is a problem for you, please us the automatic controller discovery option described above.
 
 ```typescript
 import * as methodOverride from 'method-override';
@@ -346,8 +346,8 @@ export class UsersController {
 }
 ```
 
-Note that the parameter `request` does not appear in your swagger definition file.
-Likewise you can use the decorator `@Inject` to mark a parameter as being injected manually and should be omitted in swagger generation.
+Note that the parameter `request` does not appear in your OAS file.
+Likewise you can use the decorator `@Inject` to mark a parameter as being injected manually and should be omitted in Spec generation.
 In this case you should write your own custom template where you inject the needed objects/values in the method-call.
 
 ### Dependency injection or IOC
@@ -362,7 +362,7 @@ To tell `tsoa` to use your DI-container you have to reference your module export
 The convention is that you have to name your inversify `Container` `iocContainer` and export it in the given module.
 ```json
 {
-  "swagger": {
+  "spec": {
     ...
   },
   "routes": {
@@ -463,11 +463,11 @@ import "./controllers/fooController.ts"
 
 ```
 
-### Specify error response types for Swagger
+### Specify error response types for OpenAPI
 
 ```ts
 @Response('400', 'Bad request')
-@DefaultResponse<ErrorResponse>('Unexpected error')
+@Response<ErrorResponse>('default', 'Unexpected error')
 @Get('Response')
 public async getResponse(): Promise<TestModel> {
   return new ModelService().getModel();
@@ -480,11 +480,11 @@ For information on how to return a specific error [see this example](https://git
 
 Authentication is done using a middleware handler along with `@Security('name', ['scopes'])` decorator in your controller.
 
-First, define the security definitions for swagger, and also configure where the authentication middleware handler is. In this case, it is in the `authentication.ts` file.
+First, define the security definitions for OpenAPI, and also configure where the authentication middleware handler is. In this case, it is in the `authentication.ts` file.
 
 ```json
 {
-  "swagger": {
+  "spec": {
     "securityDefinitions": {
         "api_key": {
             "type": "apiKey",
@@ -611,7 +611,7 @@ If you have a project that utilized this functionality, you can configure the in
 
 ```json
 {
-  "swagger": {
+  "spec": {
     ...
   },
   "routes": {
@@ -663,11 +663,11 @@ export class FilesController {
 }
 ```
 
-The according swagger definition can be merge-overwritten inside `tsoa.json`. Here is a quick sample, what the previous request should look like.
+The according OpenAPI definition can be merge-overwritten inside `tsoa.json`. Here is a quick sample, what the previous request should look like.
 
 ```json
 {
-  "swagger": {
+  "spec": {
     ...
     "specMerging": "recursive",
     "spec": {
@@ -698,11 +698,11 @@ The according swagger definition can be merge-overwritten inside `tsoa.json`. He
 
 ### Tags
 
-If you have a project that needs a description and/or external docs for tags, you can configure the internal generators to use the correct tags definitions and external docs by providing a tags property to swagger property in tsoa.json.
+If you have a project that needs a description and/or external docs for tags, you can configure the internal generators to use the correct tags definitions and external docs by providing a tags property to spec property in tsoa.json.
 
 ```json
 {
-  "swagger": {
+  "spec": {
     "tags":  [
       {
         "name": "User",
@@ -721,9 +721,9 @@ If you have a project that needs a description and/or external docs for tags, yo
 }
 ```
 
-### Using awesome Swagger tools
+### Using awesome OpenAPI tools
 
-Now that you have a swagger spec (swagger.json), you can use all kinds of amazing tools that [generate documentation, client SDKs, and more](http://swagger.io/).
+Now that you have a OpenAPI Specification (OAS) (swagger.json), you can use all kinds of amazing tools that [generate documentation, client SDKs, and more](http://openapi.tools//).
 
 ## Decorators
 
@@ -779,7 +779,7 @@ export class UserController {
 ### OperationId
 
 Set operationId parameter under operation's path.
-Useful for use with Swagger code generation tool since this parameter is used to name the function generated in the client SDK.
+Useful for use with OpenAPI code generation tool since this parameter is used to name the function generated in the client SDK.
 
 ```ts
 @Get()
@@ -804,7 +804,7 @@ public async find(): Promise<any> {
 
 ### Hidden
 
-Excludes this endpoint from the generated swagger document.
+Excludes this endpoint from the generated OpenAPI Specification document.
 
 ```ts
   @Get()
@@ -814,7 +814,7 @@ Excludes this endpoint from the generated swagger document.
   }
 ```
 
-It can also be set at the controller level to exclude all of its endpoints from the swagger document.
+It can also be set at the controller level to exclude all of its endpoints from the OpenAPI Specification document.
 
 ```ts
 @Hidden()
@@ -839,10 +839,10 @@ For information on the configuration object (tsoa.json), check out the following
 
 [Configuration sample](./tsoa.json)
 
-### Swagger spec generation
+### OpenAPI Specification (OAS) generation
 
 ```
-Usage: tsoa swagger [options]
+Usage: tsoa spec [options]
 
 Options:
    --configuration, -c  tsoa configuration file; default is tsoa.json in the working directory  [string]
diff --git a/src/cli.ts b/src/cli.ts
index abc564b0..a68c9dba 100644
--- a/src/cli.ts
+++ b/src/cli.ts
@@ -3,10 +3,10 @@ import * as path from 'path';
 import * as ts from 'typescript';
 import * as YAML from 'yamljs';
 import * as yargs from 'yargs';
-import { Config, RoutesConfig, SwaggerConfig } from './config';
+import { Config, RoutesConfig, SpecConfig } from './config';
 import { MetadataGenerator } from './metadataGeneration/metadataGenerator';
 import { generateRoutes } from './module/generate-routes';
-import { generateSwaggerSpec } from './module/generate-swagger-spec';
+import { generateSpec } from './module/generate-spec';
 import { fsExists, fsReadFile } from './utils/fs';
 
 const workingDir: string = process.cwd();
@@ -68,14 +68,14 @@ const validateCompilerOptions = (config?: ts.CompilerOptions): ts.CompilerOption
   return config || {};
 };
 
-export interface ExtendedSwaggerConfig extends SwaggerConfig {
+export interface ExtendedSpecConfig extends SpecConfig {
   entryFile: Config['entryFile'];
   noImplicitAdditionalProperties: Exclude<Config['noImplicitAdditionalProperties'], undefined>;
   controllerPathGlobs?: Config['controllerPathGlobs'];
 }
 
-export const validateSwaggerConfig = async (config: Config): Promise<ExtendedSwaggerConfig> => {
-  if (!config.swagger.outputDirectory) {
+export const validateSpecConfig = async (config: Config): Promise<ExtendedSpecConfig> => {
+  if (!config.spec.outputDirectory) {
     throw new Error('Missing outputDirectory: configuration must contain output directory.');
   }
   if (!config.entryFile) {
@@ -84,21 +84,21 @@ export const validateSwaggerConfig = async (config: Config): Promise<ExtendedSwa
   if (!(await fsExists(config.entryFile))) {
     throw new Error(`EntryFile not found: ${config.entryFile} - Please check your tsoa config.`);
   }
-  config.swagger.version = config.swagger.version || (await versionDefault());
+  config.spec.version = config.spec.version || (await versionDefault());
 
-  config.swagger.specVersion = config.swagger.specVersion || 2;
-  if (config.swagger.specVersion !== 2 && config.swagger.specVersion !== 3) {
+  config.spec.specVersion = config.spec.specVersion || 2;
+  if (config.spec.specVersion !== 2 && config.spec.specVersion !== 3) {
     throw new Error('Unsupported Spec version.');
   }
 
   const noImplicitAdditionalProperties = determineNoImplicitAdditionalSetting(config.noImplicitAdditionalProperties);
-  config.swagger.name = config.swagger.name || (await nameDefault());
-  config.swagger.description = config.swagger.description || (await descriptionDefault());
-  config.swagger.license = config.swagger.license || (await licenseDefault());
-  config.swagger.basePath = config.swagger.basePath || '/';
+  config.spec.name = config.spec.name || (await nameDefault());
+  config.spec.description = config.spec.description || (await descriptionDefault());
+  config.spec.license = config.spec.license || (await licenseDefault());
+  config.spec.basePath = config.spec.basePath || '/';
 
   return {
-    ...config.swagger,
+    ...config.spec,
     noImplicitAdditionalProperties,
     entryFile: config.entryFile,
     controllerPathGlobs: config.controllerPathGlobs,
@@ -188,9 +188,21 @@ if (!module.parent) {
   yargs
     .usage('Usage: $0 <command> [options]')
     .demand(1)
+    .command(
+      'spec',
+      'Generate OpenAPI spec',
+      {
+        basePath: basePathArgs,
+        configuration: configurationArgs,
+        host: hostArgs,
+        json: jsonArgs,
+        yaml: yarmlArgs,
+      },
+      SpecGenerator as any,
+    )
     .command(
       'swagger',
-      'Generate swagger spec',
+      'Generate OpenAPI spec',
       {
         basePath: basePathArgs,
         configuration: configurationArgs,
@@ -198,7 +210,7 @@ if (!module.parent) {
         json: jsonArgs,
         yaml: yarmlArgs,
       },
-      swaggerSpecGenerator as any,
+      SpecGenerator as any,
     )
     .command(
       'routes',
@@ -209,9 +221,21 @@ if (!module.parent) {
       },
       routeGenerator as any,
     )
+    .command(
+      'spec-and-routes',
+      'Generate OpenAPI spec and routes',
+      {
+        basePath: basePathArgs,
+        configuration: configurationArgs,
+        host: hostArgs,
+        json: jsonArgs,
+        yaml: yarmlArgs,
+      },
+      generateSpecAndRoutes as any,
+    )
     .command(
       'swagger-and-routes',
-      'Generate swagger and routes',
+      'Generate OpenAPI spec and routes',
       {
         basePath: basePathArgs,
         configuration: configurationArgs,
@@ -219,32 +243,32 @@ if (!module.parent) {
         json: jsonArgs,
         yaml: yarmlArgs,
       },
-      generateSwaggerAndRoutes as any,
+      generateSpecAndRoutes as any,
     )
     .help('help')
     .alias('help', 'h').argv;
 }
 
-async function swaggerSpecGenerator(args: SwaggerArgs) {
+async function SpecGenerator(args: SwaggerArgs) {
   try {
     const config = await getConfig(args.configuration);
     if (args.basePath) {
-      config.swagger.basePath = args.basePath;
+      config.spec.basePath = args.basePath;
     }
     if (args.host) {
-      config.swagger.host = args.host;
+      config.spec.host = args.host;
     }
     if (args.yaml) {
-      config.swagger.yaml = args.yaml;
+      config.spec.yaml = args.yaml;
     }
     if (args.json) {
-      config.swagger.yaml = false;
+      config.spec.yaml = false;
     }
 
     const compilerOptions = validateCompilerOptions(config.compilerOptions);
-    const swaggerConfig = await validateSwaggerConfig(config);
+    const swaggerConfig = await validateSpecConfig(config);
 
-    await generateSwaggerSpec(swaggerConfig, compilerOptions, config.ignore);
+    await generateSpec(swaggerConfig, compilerOptions, config.ignore);
   } catch (err) {
     // tslint:disable-next-line:no-console
     console.error('Generate swagger error.\n', err);
@@ -270,29 +294,29 @@ async function routeGenerator(args: ConfigArgs) {
   }
 }
 
-export async function generateSwaggerAndRoutes(args: SwaggerArgs) {
+export async function generateSpecAndRoutes(args: SwaggerArgs) {
   try {
     const config = await getConfig(args.configuration);
     if (args.basePath) {
-      config.swagger.basePath = args.basePath;
+      config.spec.basePath = args.basePath;
     }
     if (args.host) {
-      config.swagger.host = args.host;
+      config.spec.host = args.host;
     }
     if (args.yaml) {
-      config.swagger.yaml = args.yaml;
+      config.spec.yaml = args.yaml;
     }
     if (args.json) {
-      config.swagger.yaml = false;
+      config.spec.yaml = false;
     }
 
     const compilerOptions = validateCompilerOptions(config.compilerOptions);
     const routesConfig = await validateRoutesConfig(config);
-    const swaggerConfig = await validateSwaggerConfig(config);
+    const swaggerConfig = await validateSpecConfig(config);
 
     const metadata = new MetadataGenerator(routesConfig.entryFile, compilerOptions, config.ignore, routesConfig.controllerPathGlobs).Generate();
 
-    return await Promise.all([generateRoutes(routesConfig, compilerOptions, config.ignore, metadata), generateSwaggerSpec(swaggerConfig, compilerOptions, config.ignore, metadata)]);
+    return await Promise.all([generateRoutes(routesConfig, compilerOptions, config.ignore, metadata), generateSpec(swaggerConfig, compilerOptions, config.ignore, metadata)]);
   } catch (err) {
     // tslint:disable-next-line:no-console
     console.error('Generate routes error.\n', err);
diff --git a/src/config.ts b/src/config.ts
index 435d5e98..b7c904c4 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -5,7 +5,7 @@ export interface Config {
   /**
    * Swagger generation configuration object
    */
-  swagger: SwaggerConfig;
+  spec: SpecConfig;
 
   /**
    * Route generation configuration object
@@ -46,7 +46,7 @@ export interface Config {
  */
 export type DeprecatedOptionForAdditionalPropertiesHandling = true | false;
 
-export interface SwaggerConfig {
+export interface SpecConfig {
   /**
    * Generated SwaggerConfig.json will output here
    */
diff --git a/src/index.ts b/src/index.ts
index f28af80d..7f020bff 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -9,5 +9,5 @@ export * from './decorators/security';
 export * from './interfaces/controller';
 export * from './decorators/response';
 export * from './routeGeneration/templateHelpers';
-export * from './module/generate-swagger-spec';
+export * from './module/generate-spec';
 export * from './module/generate-routes';
diff --git a/src/module/generate-swagger-spec.ts b/src/module/generate-spec.ts
similarity index 88%
rename from src/module/generate-swagger-spec.ts
rename to src/module/generate-spec.ts
index 6cec7a19..e7dcba8b 100644
--- a/src/module/generate-swagger-spec.ts
+++ b/src/module/generate-spec.ts
@@ -1,7 +1,7 @@
 import * as ts from 'typescript';
 import * as YAML from 'yamljs';
-export { SwaggerConfig, Config, RoutesConfig } from '../config';
-import { ExtendedSwaggerConfig } from '../cli';
+export { SpecConfig as SwaggerConfig, Config, RoutesConfig } from '../config';
+import { ExtendedSpecConfig } from '../cli';
 import { MetadataGenerator } from '../metadataGeneration/metadataGenerator';
 import { Tsoa } from '../metadataGeneration/tsoa';
 import { SpecGenerator2 } from '../swagger/specGenerator2';
@@ -9,8 +9,8 @@ import { SpecGenerator3 } from '../swagger/specGenerator3';
 import { Swagger } from '../swagger/swagger';
 import { fsExists, fsMkDir, fsWriteFile } from '../utils/fs';
 
-export const generateSwaggerSpec = async (
-  swaggerConfig: ExtendedSwaggerConfig,
+export const generateSpec = async (
+  swaggerConfig: ExtendedSpecConfig,
   compilerOptions?: ts.CompilerOptions,
   ignorePaths?: string[],
   /**
diff --git a/src/swagger/specGenerator.ts b/src/swagger/specGenerator.ts
index d26106fa..b3acbf00 100644
--- a/src/swagger/specGenerator.ts
+++ b/src/swagger/specGenerator.ts
@@ -1,10 +1,10 @@
-import { ExtendedSwaggerConfig } from '../cli';
+import { ExtendedSpecConfig } from '../cli';
 import { Tsoa } from '../metadataGeneration/tsoa';
 import { assertNever } from './../utils/assertNever';
 import { Swagger } from './swagger';
 
 export abstract class SpecGenerator {
-  constructor(protected readonly metadata: Tsoa.Metadata, protected readonly config: ExtendedSwaggerConfig) {}
+  constructor(protected readonly metadata: Tsoa.Metadata, protected readonly config: ExtendedSpecConfig) {}
 
   protected buildAdditionalProperties(type: Tsoa.Type) {
     return this.getSwaggerType(type);
diff --git a/src/swagger/specGenerator2.ts b/src/swagger/specGenerator2.ts
index 4fe85617..8a2233bb 100644
--- a/src/swagger/specGenerator2.ts
+++ b/src/swagger/specGenerator2.ts
@@ -1,4 +1,4 @@
-import { ExtendedSwaggerConfig } from '../cli';
+import { ExtendedSpecConfig } from '../cli';
 import { Tsoa } from '../metadataGeneration/tsoa';
 import { assertNever } from '../utils/assertNever';
 import { isVoidType } from '../utils/isVoidType';
@@ -7,7 +7,7 @@ import { SpecGenerator } from './specGenerator';
 import { Swagger } from './swagger';
 
 export class SpecGenerator2 extends SpecGenerator {
-  constructor(protected readonly metadata: Tsoa.Metadata, protected readonly config: ExtendedSwaggerConfig) {
+  constructor(protected readonly metadata: Tsoa.Metadata, protected readonly config: ExtendedSpecConfig) {
     super(metadata, config);
   }
 
diff --git a/src/swagger/specGenerator3.ts b/src/swagger/specGenerator3.ts
index 128372c4..e30e64e7 100644
--- a/src/swagger/specGenerator3.ts
+++ b/src/swagger/specGenerator3.ts
@@ -1,4 +1,4 @@
-import { ExtendedSwaggerConfig } from '../cli';
+import { ExtendedSpecConfig } from '../cli';
 import { Tsoa } from '../metadataGeneration/tsoa';
 import { assertNever } from '../utils/assertNever';
 import { isVoidType } from '../utils/isVoidType';
@@ -17,7 +17,7 @@ import { Swagger } from './swagger';
  * Also accept OpenAPI 3.0.0 metadata, like components/securitySchemes instead of securityDefinitions
  */
 export class SpecGenerator3 extends SpecGenerator {
-  constructor(protected readonly metadata: Tsoa.Metadata, protected readonly config: ExtendedSwaggerConfig) {
+  constructor(protected readonly metadata: Tsoa.Metadata, protected readonly config: ExtendedSpecConfig) {
     super(metadata, config);
   }
 
diff --git a/tsoa.json b/tsoa.json
index e422184e..9bffc3ec 100644
--- a/tsoa.json
+++ b/tsoa.json
@@ -1,7 +1,7 @@
 {
     "entryFile": "./tests/fixtures/express/server.ts",
     "noImplicitAdditionalProperties": "silently-remove-extras",
-    "swagger": {
+    "spec": {
         "outputDirectory": "./dist",
         "host": "localhost:3000",
         "basePath": "/v1",


Test patch:
diff --git a/tests/fixtures/defaultOptions.ts b/tests/fixtures/defaultOptions.ts
index c839883a..cd8eca4b 100644
--- a/tests/fixtures/defaultOptions.ts
+++ b/tests/fixtures/defaultOptions.ts
@@ -1,4 +1,4 @@
-import { ExtendedSwaggerConfig } from '../../src/cli';
+import { ExtendedSpecConfig } from '../../src/cli';
 import { Config } from './../../src/config';
 export function getDefaultOptions(outputDirectory: string = '', entryFile: string = ''): Config {
   return {
@@ -7,7 +7,7 @@ export function getDefaultOptions(outputDirectory: string = '', entryFile: strin
     routes: {
       routesDir: './build',
     },
-    swagger: {
+    spec: {
       basePath: '/v1',
       description: 'Description of a test API',
       host: 'localhost:3000',
@@ -61,10 +61,10 @@ export function getDefaultOptions(outputDirectory: string = '', entryFile: strin
   };
 }
 
-export function getDefaultExtendedOptions(outputDirectory: string = '', entryFile: string = ''): ExtendedSwaggerConfig {
+export function getDefaultExtendedOptions(outputDirectory: string = '', entryFile: string = ''): ExtendedSpecConfig {
   const defaultOptions = getDefaultOptions(outputDirectory, entryFile);
   return {
-    ...defaultOptions.swagger,
+    ...defaultOptions.spec,
     entryFile,
     noImplicitAdditionalProperties: 'ignore',
     controllerPathGlobs: defaultOptions.controllerPathGlobs,
diff --git a/tests/prepare.ts b/tests/prepare.ts
index 837df0e9..f0ea0e64 100644
--- a/tests/prepare.ts
+++ b/tests/prepare.ts
@@ -1,11 +1,11 @@
 // tslint:disable:no-console
 import chalk from 'chalk';
-import { generateSwaggerAndRoutes } from '../src/cli';
+import { generateSpecAndRoutes } from '../src/cli';
 import { generateRoutes } from '../src/module/generate-routes';
 import { Timer } from './utils/timer';
 
 const spec = async () => {
-  const result = await generateSwaggerAndRoutes({
+  const result = await generateSpecAndRoutes({
     configuration: 'tsoa.json',
   });
   return result[0];
diff --git a/tests/unit/swagger/config.spec.ts b/tests/unit/swagger/config.spec.ts
index 00433a0c..17a8546b 100644
--- a/tests/unit/swagger/config.spec.ts
+++ b/tests/unit/swagger/config.spec.ts
@@ -1,6 +1,6 @@
 import { expect } from 'chai';
 import 'mocha';
-import { validateSwaggerConfig, ExtendedSwaggerConfig } from '../../../src/cli';
+import { validateSpecConfig, ExtendedSpecConfig } from '../../../src/cli';
 import { Config } from '../../../src/config';
 import { getDefaultOptions } from '../../fixtures/defaultOptions';
 
@@ -8,7 +8,7 @@ describe('Configuration', () => {
   describe('.validateSwaggerConfig', () => {
     it('should reject when outputDirectory is not set', done => {
       const config: Config = getDefaultOptions();
-      validateSwaggerConfig(config).then(
+      validateSpecConfig(config).then(
         result => {
           throw new Error('Should not get here, expecting error regarding outputDirectory');
         },
@@ -21,7 +21,7 @@ describe('Configuration', () => {
 
     it('should reject when entryFile is not set', done => {
       const config: Config = getDefaultOptions('some/output/directory');
-      validateSwaggerConfig(config).then(
+      validateSpecConfig(config).then(
         result => {
           throw new Error('Should not get here, expecting error regarding entryFile');
         },
@@ -34,7 +34,7 @@ describe('Configuration', () => {
 
     it('should set the default API version', done => {
       const config: Config = getDefaultOptions('some/output/directory', 'tsoa.json');
-      validateSwaggerConfig(config).then((configResult: ExtendedSwaggerConfig) => {
+      validateSpecConfig(config).then((configResult: ExtendedSpecConfig) => {
         expect(configResult.version).to.equal('1.0.0');
         done();
       });
@@ -42,7 +42,7 @@ describe('Configuration', () => {
 
     it('should set the default Spec version 2 when not specified', done => {
       const config: Config = getDefaultOptions('some/output/directory', 'tsoa.json');
-      validateSwaggerConfig(config).then((configResult: ExtendedSwaggerConfig) => {
+      validateSpecConfig(config).then((configResult: ExtendedSpecConfig) => {
         expect(configResult.specVersion).to.equal(2);
         done();
       });
@@ -51,9 +51,9 @@ describe('Configuration', () => {
     it('should reject an unsupported Spec version', done => {
       const config: Config = getDefaultOptions('some/output/directory', 'tsoa.json');
       // Do any cast to ignore compile error due to Swagger.SupportedSpecVersion not supporting -2
-      config.swagger.specVersion = -2 as any;
-      validateSwaggerConfig(config).then(
-        (configResult: ExtendedSwaggerConfig) => {
+      config.spec.specVersion = -2 as any;
+      validateSpecConfig(config).then(
+        (configResult: ExtendedSpecConfig) => {
           throw new Error('Should not get here, expecting error regarding unsupported Spec version');
         },
         err => {
@@ -65,8 +65,8 @@ describe('Configuration', () => {
 
     it('should accept Spec version 3 when specified', done => {
       const config: Config = getDefaultOptions('some/output/directory', 'tsoa.json');
-      config.swagger.specVersion = 3;
-      validateSwaggerConfig(config).then((configResult: ExtendedSwaggerConfig) => {
+      config.spec.specVersion = 3;
+      validateSpecConfig(config).then((configResult: ExtendedSpecConfig) => {
         expect(configResult.specVersion).to.equal(3);
         done();
       });
diff --git a/tests/unit/swagger/definitionsGeneration/definitions.spec.ts b/tests/unit/swagger/definitionsGeneration/definitions.spec.ts
index 2f343ee9..44ae2d8d 100644
--- a/tests/unit/swagger/definitionsGeneration/definitions.spec.ts
+++ b/tests/unit/swagger/definitionsGeneration/definitions.spec.ts
@@ -5,14 +5,14 @@ import { SpecGenerator2 } from '../../../../src/swagger/specGenerator2';
 import { Swagger } from '../../../../src/swagger/swagger';
 import { getDefaultOptions } from '../../../fixtures/defaultOptions';
 import { TestModel } from '../../../fixtures/testModel';
-import { ExtendedSwaggerConfig } from '../../../../src/cli';
+import { ExtendedSpecConfig } from '../../../../src/cli';
 
 describe('Definition generation', () => {
   const metadata = new MetadataGenerator('./tests/fixtures/controllers/getController.ts').Generate();
   const dynamicMetadata = new MetadataGenerator('./tests/fixtures/controllers/getController.ts', undefined, undefined, ['./tests/fixtures/controllers/getController.ts']).Generate();
   const defaultConfig = getDefaultOptions();
-  const defaultOptions: ExtendedSwaggerConfig = { ...defaultConfig.swagger, entryFile: defaultConfig.entryFile, noImplicitAdditionalProperties: 'ignore' };
-  const optionsWithNoAdditional = Object.assign<{}, ExtendedSwaggerConfig, Partial<ExtendedSwaggerConfig>>({}, defaultOptions, {
+  const defaultOptions: ExtendedSpecConfig = { ...defaultConfig.spec, entryFile: defaultConfig.entryFile, noImplicitAdditionalProperties: 'ignore' };
+  const optionsWithNoAdditional = Object.assign<{}, ExtendedSpecConfig, Partial<ExtendedSpecConfig>>({}, defaultOptions, {
     noImplicitAdditionalProperties: 'silently-remove-extras',
   });
 
diff --git a/tests/unit/swagger/parameterDetails3.spec.ts b/tests/unit/swagger/parameterDetails3.spec.ts
index 3e32619e..4d7754f1 100644
--- a/tests/unit/swagger/parameterDetails3.spec.ts
+++ b/tests/unit/swagger/parameterDetails3.spec.ts
@@ -4,14 +4,14 @@ import { MetadataGenerator } from '../../../src/metadataGeneration/metadataGener
 import { SpecGenerator3 } from '../../../src/swagger/specGenerator3';
 import { Swagger } from '../../../src/swagger/swagger';
 import { getDefaultOptions } from '../../fixtures/defaultOptions';
-import { ExtendedSwaggerConfig } from '../../../src/cli';
+import { ExtendedSpecConfig } from '../../../src/cli';
 
 describe('Parameter generation for OpenAPI 3.0.0', () => {
   const metadata = new MetadataGenerator('./tests/fixtures/controllers/parameterController.ts').Generate();
 
   const defaultConfig = getDefaultOptions();
-  const defaultOptions: ExtendedSwaggerConfig = { ...defaultConfig.swagger, noImplicitAdditionalProperties: 'ignore', entryFile: defaultConfig.entryFile };
-  const optionsWithNoAdditional = Object.assign<{}, ExtendedSwaggerConfig, Partial<ExtendedSwaggerConfig>>({}, defaultOptions, {
+  const defaultOptions: ExtendedSpecConfig = { ...defaultConfig.spec, noImplicitAdditionalProperties: 'ignore', entryFile: defaultConfig.entryFile };
+  const optionsWithNoAdditional = Object.assign<{}, ExtendedSpecConfig, Partial<ExtendedSpecConfig>>({}, defaultOptions, {
     noImplicitAdditionalProperties: 'silently-remove-extras',
   });
 
diff --git a/tests/unit/swagger/schemaDetails.spec.ts b/tests/unit/swagger/schemaDetails.spec.ts
index ee8ef831..127bfb0a 100644
--- a/tests/unit/swagger/schemaDetails.spec.ts
+++ b/tests/unit/swagger/schemaDetails.spec.ts
@@ -6,7 +6,7 @@ import { MetadataGenerator } from '../../../src/metadataGeneration/metadataGener
 import { SpecGenerator2 } from '../../../src/swagger/specGenerator2';
 import { getDefaultExtendedOptions } from '../../fixtures/defaultOptions';
 import { Tsoa } from '../../../src/metadataGeneration/tsoa';
-import { ExtendedSwaggerConfig } from '../../../src/cli';
+import { ExtendedSpecConfig } from '../../../src/cli';
 
 describe('Schema details generation', () => {
   const metadata = new MetadataGenerator('./tests/fixtures/controllers/getController.ts').Generate();
@@ -89,7 +89,7 @@ describe('Schema details generation', () => {
           },
         },
       };
-      const swaggerConfig: ExtendedSwaggerConfig = {
+      const swaggerConfig: ExtendedSpecConfig = {
         outputDirectory: 'mockOutputDirectory',
         entryFile: 'mockEntryFile',
         noImplicitAdditionalProperties: 'ignore',
@@ -108,7 +108,7 @@ describe('Schema details generation', () => {
     });
 
     it('should throw if an enum is mixed with numbers and strings', () => {
-      const swaggerConfig: ExtendedSwaggerConfig = {
+      const swaggerConfig: ExtendedSpecConfig = {
         outputDirectory: 'mockOutputDirectory',
         entryFile: 'mockEntryFile',
         noImplicitAdditionalProperties: 'ignore',
diff --git a/tests/unit/swagger/schemaDetails3.spec.ts b/tests/unit/swagger/schemaDetails3.spec.ts
index 7ed42c9b..876c77df 100644
--- a/tests/unit/swagger/schemaDetails3.spec.ts
+++ b/tests/unit/swagger/schemaDetails3.spec.ts
@@ -6,13 +6,13 @@ import { SpecGenerator3 } from '../../../src/swagger/specGenerator3';
 import { Swagger } from '../../../src/swagger/swagger';
 import { getDefaultExtendedOptions } from '../../fixtures/defaultOptions';
 import { TestModel } from '../../fixtures/duplicateTestModel';
-import { ExtendedSwaggerConfig } from '../../../src/cli';
+import { ExtendedSpecConfig } from '../../../src/cli';
 
 describe('Definition generation for OpenAPI 3.0.0', () => {
   const metadata = new MetadataGenerator('./tests/fixtures/controllers/getController.ts').Generate();
 
-  const defaultOptions: ExtendedSwaggerConfig = getDefaultExtendedOptions();
-  const optionsWithNoAdditional = Object.assign<{}, ExtendedSwaggerConfig, Partial<ExtendedSwaggerConfig>>({}, defaultOptions, {
+  const defaultOptions: ExtendedSpecConfig = getDefaultExtendedOptions();
+  const optionsWithNoAdditional = Object.assign<{}, ExtendedSpecConfig, Partial<ExtendedSpecConfig>>({}, defaultOptions, {
     noImplicitAdditionalProperties: 'silently-remove-extras',
   });
 
@@ -73,7 +73,7 @@ describe('Definition generation for OpenAPI 3.0.0', () => {
     });
 
     it('should have relative URL when no host is defined', () => {
-      const optionsWithNoHost = Object.assign<{}, ExtendedSwaggerConfig>({}, defaultOptions);
+      const optionsWithNoHost = Object.assign<{}, ExtendedSpecConfig>({}, defaultOptions);
       delete optionsWithNoHost.host;
 
       const spec: Swagger.Spec3 = new SpecGenerator3(metadata, optionsWithNoHost).GetSpec();
@@ -1274,7 +1274,7 @@ describe('Definition generation for OpenAPI 3.0.0', () => {
           },
         },
       };
-      const swaggerConfig: ExtendedSwaggerConfig = {
+      const swaggerConfig: ExtendedSpecConfig = {
         outputDirectory: 'mockOutputDirectory',
         entryFile: 'mockEntryFile',
         noImplicitAdditionalProperties: 'ignore',