Repository: lukeautry/tsoa (ts)

Issue:
Validation: Set defaults for optional params
<!--- Provide a general summary of the issue in the Title above -->

## Sorting

* **I'm submitting a ...**
  - [x] bug report
  - [ ] 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
```
interface WithDefaults {
  /**
   * @isInt
   * @default 666
   */
  myNumber?: number;
}
```
sets 666 when no number gets sent in.

## Current Behavior
Generated metadata is correct, however, nothing is set during validation.

This happens because tsoa only sets defaults for required parameters (there is an explicit check).

## Possible Solution
Should set the default if `undefined`

## Breaking change?
potentially

This might apply for other validations aswell.

Pull request:
ParamValidation: Apply defaults for optional properties
### 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?
* [x] 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 #537

### 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**

None I'm aware of

**Breaking?**
No

@dgreene1 if you can manage to review a PR on top of your work, I'd appreciate if it could be this one.

Patch:
diff --git a/src/routeGeneration/templateHelpers.ts b/src/routeGeneration/templateHelpers.ts
index b5fbd1ec..6250761f 100644
--- a/src/routeGeneration/templateHelpers.ts
+++ b/src/routeGeneration/templateHelpers.ts
@@ -21,9 +21,12 @@ export function ValidateParam(
 export class ValidationService {
   constructor(private readonly models: TsoaRoute.Models) {}
 
-  public ValidateParam(property: TsoaRoute.PropertySchema, value: any, name = '', fieldErrors: FieldErrors, parent = '', minimalSwaggerConfig: SwaggerConfigRelatedToRoutes) {
+  public ValidateParam(property: TsoaRoute.PropertySchema, rawValue: any, name = '', fieldErrors: FieldErrors, parent = '', minimalSwaggerConfig: SwaggerConfigRelatedToRoutes) {
+    let value = rawValue;
     if (value === undefined || value === null) {
-      if (property.required) {
+      if (property.default !== undefined) {
+        value = property.default;
+      } else if (property.required) {
         let message = `'${name}' is required`;
         if (property.validators) {
           const validators = property.validators;
@@ -40,7 +43,7 @@ export class ValidationService {
         };
         return;
       } else {
-        return property.default !== undefined ? property.default : value;
+        return value;
       }
     }
 


Test patch:
diff --git a/tests/unit/swagger/templateHelpers.spec.ts b/tests/unit/swagger/templateHelpers.spec.ts
index 900aad8c..e27bae36 100644
--- a/tests/unit/swagger/templateHelpers.spec.ts
+++ b/tests/unit/swagger/templateHelpers.spec.ts
@@ -1,7 +1,7 @@
 import { expect } from 'chai';
 import 'mocha';
 import { SwaggerConfigRelatedToRoutes } from '../../../src/routeGeneration/routeGenerator';
-import { FieldErrors, ValidationService } from './../../../src/routeGeneration/templateHelpers';
+import { FieldErrors, ValidationService, TsoaRoute } from './../../../src/routeGeneration/templateHelpers';
 
 describe('ValidationService', () => {
   describe('Model validate', () => {
@@ -339,6 +339,38 @@ describe('ValidationService', () => {
     });
   });
 
+  describe('Param validate', () => {
+    it('Should apply defaults for optional properties', () => {
+      const value = undefined;
+      const propertySchema: TsoaRoute.PropertySchema = { dataType: 'integer', default: '666', required: false, validators: {} };
+      const minimalSwaggerConfig: SwaggerConfigRelatedToRoutes = {
+        noImplicitAdditionalProperties: undefined,
+      };
+      const result = new ValidationService({}).ValidateParam(propertySchema, value, 'defaultProp', {}, undefined, minimalSwaggerConfig);
+      expect(result).to.equal(666);
+    });
+
+    it('Should not override values with defaults', () => {
+      const value = 123;
+      const propertySchema: TsoaRoute.PropertySchema = { dataType: 'integer', default: '666', required: false, validators: {} };
+      const minimalSwaggerConfig: SwaggerConfigRelatedToRoutes = {
+        noImplicitAdditionalProperties: undefined,
+      };
+      const result = new ValidationService({}).ValidateParam(propertySchema, value, 'defaultProp', {}, undefined, minimalSwaggerConfig);
+      expect(result).to.equal(123);
+    });
+
+    it('Should apply defaults for required properties', () => {
+      const value = undefined;
+      const propertySchema: TsoaRoute.PropertySchema = { dataType: 'integer', default: '666', required: true, validators: {} };
+      const minimalSwaggerConfig: SwaggerConfigRelatedToRoutes = {
+        noImplicitAdditionalProperties: undefined,
+      };
+      const result = new ValidationService({}).ValidateParam(propertySchema, value, 'defaultProp', {}, undefined, minimalSwaggerConfig);
+      expect(result).to.equal(666);
+    });
+  });
+
   describe('Integer validate', () => {
     it('should integer value', () => {
       const value = '10';