Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uses CoerceTypes option passed. #809

Merged
merged 2 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading