Repository: lukeautry/tsoa (ts)

Issue:
Support for relative `host` in openapi 3
<!--- Provide a general summary of the issue in the Title above -->

## Sorting

* **I'm submitting a ...**
  - [ ] bug report
  - [x] feature request
  - [ ] support request

* I confirm that I
  - [x] used the [search](https://github.com/lukeautry/tsoa/search?type=Issues) to make sure that a similar issue hasn't already been submit

## Expected Behavior

Have in the output something like
```json
	"servers": [
		{
			"url": "/v1"
		}
	]
```

I'd like to be able to specify relative `host`, which is allowed by specification https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#fixed-fields-4.

## Current Behavior
Currently if I omit `host` field in the `swagger` config or use empty `"host": ""`, it gets replaced with `http://localhost:3000`. Using `"host": "/"` also doesn't work.

## Possible Solution

## Steps to Reproduce

## Context (Environment)
Version of the library: 2.5.9
Version of NodeJS: 12
* Confirm you were using yarn not npm: [ ]

## Detailed Description

## Breaking change?


Pull request description:
Allow relative locations for OpenApi server URLs
### 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?
* [x] 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?

**Closing issues**
closes #540 

### 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?

**Potential Problems With The Approach**

This introduces the possibility of having relative URLs by setting the host explicitly to null.
Doing it that way will not introduce a breaking change.
Although as a downside i do not currently see a possibility to specify this value as a argument to the _--host_ cli parameter

It was suggested in the issue that in the next major version this behavior could be adapted that _all_ values of host which evaluate to _false_ could behave that way, could there be anything more done to not forget about this adaption for this next version? i.e. is there a list of ideas for breaking changes for the next version?

**Test plan**

Added test which explicitly checks if the URL is only "/v1/" which is in accordance to the OA 3.0 specs (see issue)

Patch:
diff --git a/src/config.ts b/src/config.ts
index fa8889b3..705aea92 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -48,9 +48,9 @@ export interface SwaggerConfig {
   noImplicitAdditionalProperties?: 'throw-on-extras' | 'silently-remove-extras' | DeprecatedOptionForAdditionalPropertiesHandling;
 
   /**
-   * API host, expressTemplate.g. localhost:3000 or myapi.com
+   * API host, expressTemplat e.g. localhost:3000 or myapi.com, use null for relative urls
    */
-  host?: string;
+  host?: string | null;
 
   /**
    * API version number; defaults to npm package version
diff --git a/src/swagger/specGenerator3.ts b/src/swagger/specGenerator3.ts
index e1205ca6..1d4aca74 100644
--- a/src/swagger/specGenerator3.ts
+++ b/src/swagger/specGenerator3.ts
@@ -94,10 +94,18 @@ export class SpecGenerator3 extends SpecGenerator {
   private buildServers() {
     const basePath = normalisePath(this.config.basePath as string, '/', undefined, false);
     const scheme = this.config.schemes ? this.config.schemes[0] : 'https';
-    const host = this.config.host || 'localhost:3000';
+
+    let url;
+    if (this.config.host === null) {
+      url = basePath;
+    } else {
+      const host = this.config.host || 'localhost:3000';
+      url = `${scheme}://${host}${basePath}`;
+    }
+
     return [
       {
-        url: `${scheme}://${host}${basePath}`,
+        url,
       } as Swagger.Server,
     ];
   }


Test patch:
diff --git a/tests/unit/swagger/schemaDetails3.spec.ts b/tests/unit/swagger/schemaDetails3.spec.ts
index d4df56a5..7ab120ba 100644
--- a/tests/unit/swagger/schemaDetails3.spec.ts
+++ b/tests/unit/swagger/schemaDetails3.spec.ts
@@ -74,6 +74,15 @@ describe('Definition generation for OpenAPI 3.0.0', () => {
       expect(specDefault.spec).to.not.have.property('basePath');
       expect(specDefault.spec.servers[0].url).to.match(/\/v1/);
     });
+
+    it('setting host to null should result in relative URL', () => {
+      const optionsWithHostIsNull = Object.assign<{}, SwaggerConfig, Partial<SwaggerConfig>>({}, defaultOptions, {
+        host: null,
+      });
+      const spec: Swagger.Spec3 = new SpecGenerator3(metadata, optionsWithHostIsNull).GetSpec();
+
+      expect(spec.servers[0].url).to.equal('/v1');
+    });
   });
 
   describe('security', () => {