Skip to content

Commit

Permalink
pass coerceTypes through (#809)
Browse files Browse the repository at this point in the history
Co-authored-by: Carmine DiMascio <[email protected]>
  • Loading branch information
daneryl and cdimascio authored Jun 2, 2024
1 parent e35a07c commit 8f7c678
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 9 deletions.
10 changes: 9 additions & 1 deletion src/middlewares/openapi.request.validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ export class RequestValidator {
delete this.apiDoc.components?.examples;
this.requestOpts.allowUnknownQueryParameters =
options.allowUnknownQueryParameters;
this.ajv = createRequestAjv(apiDoc, { ...options, coerceTypes: true });

this.ajv = createRequestAjv(
apiDoc,
// This should always be true as it handles query params (everything, but the body)
// This should always be coerced. Note that coerceTypes = 'array` also operates as true
// but also coerces 'array' types
!options.coerceTypes ? { ...options, coerceTypes: true } : options,
);
this.ajvBody = createRequestAjv(apiDoc, options);
}

Expand Down Expand Up @@ -220,6 +227,7 @@ export class RequestValidator {
}
}
});
return null;
}

private discriminatorValidator(req, discriminator) {
Expand Down
40 changes: 32 additions & 8 deletions test/coercion.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,34 @@ import * as packageJson from '../package.json';

describe(packageJson.name, () => {
let app = null;
let arrayCoercedApp = null;

before(async () => {
// Set up the express app
const apiSpec = path.join('test', 'resources', 'coercion.yaml');
const routes = express
.Router()
.post(`/pets`, (req, res) => res.json(req.body))
.post(`/pets_string_boolean`, (req, res) => res.json(req.body))
.get(`/pets_as_array_parameter`, (req, res) => res.json(req.query));

app = await createApp({ apiSpec }, 3005, (app) =>
app.use(
`${app.basePath}/coercion`,
express
.Router()
.post(`/pets`, (req, res) => res.json(req.body))
.post(`/pets_string_boolean`, (req, res) => res.json(req.body)),
),
app.use(`${app.basePath}/coercion`, routes),
);
arrayCoercedApp = await createApp(
{ apiSpec, validateRequests: { coerceTypes: 'array' } },
3006,
(appWithCoerceTypes) =>
appWithCoerceTypes.use(
`${appWithCoerceTypes.basePath}/coercion`,
routes,
),
);
});

after(() => {
app.server.close();
arrayCoercedApp.server.close();
});

it('should return 400 since is_cat is passed as string not boolean', async () =>
Expand All @@ -35,7 +46,9 @@ describe(packageJson.name, () => {
})
.expect(400)
.then((r) => {
expect(r.body.message).to.contain('request/body/is_cat must be boolean');
expect(r.body.message).to.contain(
'request/body/is_cat must be boolean',
);
}));

it('should return 400 when age is passed as string, but number is expected', async () =>
Expand Down Expand Up @@ -102,4 +115,15 @@ describe(packageJson.name, () => {
.then((r) => {
expect(r.body.message).to.contain('request/body/is_cat must be string');
}));

it('should return 200 when names is a string and coerce names to be an array', async () =>
request(arrayCoercedApp)
.get(`${arrayCoercedApp.basePath}/coercion/pets_as_array_parameter`)
.query({
filter: { names: 'test' },
})
.expect(200)
.then((r) => {
expect(r.text).to.equal('{"filter":{"names":["test"]}}');
}));
});
24 changes: 24 additions & 0 deletions test/resources/coercion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,30 @@ paths:
schema:
$ref: '#/components/schemas/PetStringBoolean'

/coercion/pets_as_array_parameter:
get:
description: Returns pets by name
operationId: addPet
parameters:
- in: query
name: filter
schema:
type: object
additionalProperties: false
properties:
names:
type: array
items:
type: string
responses:
'200':
description: pet response
content:
application/json:
schema:
type: array
items: { $ref: '#/components/schemas/Pet' }

components:
schemas:
Pet:
Expand Down

0 comments on commit 8f7c678

Please sign in to comment.