Skip to content

Commit

Permalink
Query parameters validation #31
Browse files Browse the repository at this point in the history
  • Loading branch information
Carmine DiMascio committed Sep 9, 2019
1 parent 9491a0a commit 9940fe6
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 5 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "express-openapi-validator",
"version": "1.8.0",
"version": "2.0.0",
"description": "Automatically validate API requests using an OpenAPI 3 and Express.",
"main": "dist/index.js",
"scripts": {
Expand Down
15 changes: 15 additions & 0 deletions src/middlewares/openapi.request.validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ export class RequestValidator {
const validator = this.ajv.compile(schema);

return (req, res, next) => {
this.rejectUnknownQueryParams(req.query, schema.properties.query);

const shouldUpdatePathParams =
Object.keys(req.openapi.pathParams).length > 0;

Expand Down Expand Up @@ -262,6 +264,19 @@ export class RequestValidator {
};
}

private rejectUnknownQueryParams(query, schema) {
if (!schema.properties) return;
const knownQueryParams = new Set(Object.keys(schema.properties));
const queryParams = Object.keys(query);
for (const q of queryParams) {
if (!knownQueryParams.has(q)) {
const message = `Unknown query parameter ${q}`;
const err = validationError(400, `.query.${q}`, message);
throw ono(err, message);
}
}
}

private requestBodyToSchema(path, contentType, requestBody: any = {}) {
if (requestBody.content) {
const content = requestBody.content[contentType];
Expand Down
55 changes: 55 additions & 0 deletions test/query.params.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as path from 'path';
import * as express from 'express';
import { expect } from 'chai';
import * as request from 'supertest';
import { createApp } from './common/app';

const packageJson = require('../package.json');

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

before(async () => {
// Set up the express app
const apiSpec = path.join('test', 'resources', 'query.params.yaml');
app = await createApp({ apiSpec }, 3005);
basePath = app.basePath;

app.use(
`${basePath}`,
express.Router().post(`/pets/nullable`, (req, res) => res.json(req.body)),
);
});

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

it('should pass if known query params are specified', async () =>
request(app)
.get(`${basePath}/pets`)
.query({
tags: 'one,two,three',
limit: 10,
breed: 'german_shepherd',
owner_name: 'carmine',
})
.expect(200));

it('should fail if unknown query param is specified', async () =>
request(app)
.get(`${basePath}/pets`)
.query({
tags: 'one,two,three',
limit: 10,
breed: 'german_shepherd',
owner_name: 'carmine',
unknown_prop: 'test',
})
.expect(400)
.then(r => {
console.log(r.body);
expect(r.body.errors).to.be.an('array');
}));
});
104 changes: 104 additions & 0 deletions test/resources/query.params.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
openapi: '3.0.0'
info:
version: 1.0.0
title: Swagger Petstore
description: A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification
termsOfService: http://swagger.io/terms/
contact:
name: Swagger API Team
email: apiteam@swagger.io
url: http://swagger.io
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
servers:
- url: /v1/
- url: http://{name}.swagger.io:{port}/{version}
variables:
name:
default: petstore
enum:
- petstore
- storeofpets
port:
enum:
- '443'
- '8443'
default: '443'
version:
default: v1
enum:
- v1
paths:
/pets:
get:
description: |
Returns all pets from the system that the user has access tp
parameters:
- name: tags
in: query
description: tags to filter by
required: false
style: form
schema:
type: array
items:
type: string
- name: limit
in: query
description: maximum number of results to return
required: true
schema:
type: integer
format: int32
minimum: 5
- name: breed
in: query
description: maximum number of results to return
required: true
schema:
type: string
enum:
- german_shepherd
- golden_retreiver
- $ref: '#/components/parameters/owner_name'
responses:
'200':
description: pet response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
components:
parameters:
owner_name:
name: owner_name
in: query
description: owner's name
required: true
schema:
type: string

schemas:
NewPet:
additionalProperties: false
required:
- name
properties:
name:
type: string
nullable: true
tag:
type: string

Pet:
allOf:
- $ref: '#/components/schemas/NewPet'
- required:
- id
properties:
id:
type: integer
format: int64
6 changes: 3 additions & 3 deletions test/routes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,17 @@ describe(packageJson.name, () => {
// .expect('Content-Type', /json/)
.expect(200));

it('should return 200 with unknown query parameter', async () =>
it('should return 400 with unknown query parameter', async () =>
request(apps[i])
.get(`${basePath}/pets`)
.query({
test: 'one',
limit: 10,
bad_param: 'test',
unknown_param: 'test',
})
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200));
.expect(400));

it('should return 400 when improper range specified', async () =>
request(apps[i])
Expand Down

0 comments on commit 9940fe6

Please sign in to comment.