Skip to content

Commit

Permalink
Allow wildcard content types and conntent types with parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
jordandobrev committed Apr 10, 2020
1 parent 53e53d7 commit 446fad9
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 4 deletions.
21 changes: 20 additions & 1 deletion src/middlewares/parsers/body.parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,33 @@ export class BodySchemaParser {
}

if (!content) {
const msg =
for (const requestContentType of Object.keys(requestBody.content)) {
if (requestContentType === '*/*') {
content = requestBody.content[requestContentType];
break;
}

if (!new RegExp(/^[a-z]+\/\*$/).test(requestContentType)) continue; // not a wildcard of type application/*

const [type] = requestContentType.split('/', 1);

if (new RegExp(`^${type}\/.+$`).test(contentType.contentType)) {
content = requestBody.content[requestContentType];
break;
}
}
}

if (!content) {
const msg =
contentType.contentType === 'not_provided'
? 'media type not specified'
: `unsupported media type ${contentType.contentType}`;
throw validationError(415, path, msg);
}

const schema = this.cleanseContentSchema(contentType, requestBody);

return schema ?? content.schema ?? {};
}
return {};
Expand Down
5 changes: 4 additions & 1 deletion test/common/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ export async function createApp(
(<any>app).basePath = '/v1';

app.use(bodyParser.json());
app.use(bodyParser.json({ type: 'application/hal+json' }));
app.use(bodyParser.json({ type: 'application/*+json' }));
app.use(bodyParser.json({ type: 'application/*+json*' }));

app.use(bodyParser.text());
app.use(bodyParser.text({ type: 'text/html' }));
app.use(logger('dev'));
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
Expand Down
49 changes: 49 additions & 0 deletions test/request.bodies.ref.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ describe(packageJson.name, () => {
app.post(`${app.basePath}/request_bodies_ref`, (req, res) => {
if (req.header('accept') && req.header('accept').indexOf('text/plain') > -1) {
res.type('text').send(req.body);
} else if (req.header('accept') && req.header('accept').indexOf('text/html') > -1) {
res.type('html').send(req.body);
} else if (req.header('accept') && req.header('accept').indexOf('application/hal+json') > -1) {
res.type('application/hal+json').send(req.body);
} else if (req.header('accept') && req.header('accept').indexOf('application/vnd.api+json') > -1) {
res.type(req.header('accept')).send(req.body);
} else if (req.query.bad_body) {
const r = req.body;
r.unexpected_prop = 'bad';
Expand Down Expand Up @@ -54,6 +58,51 @@ describe(packageJson.name, () => {
});
});

it('should return 200 if text/html request body is satisfied by */*', async () => {
const stringData = '<html><body>my html data</body></html>';
return request(app)
.post(`${app.basePath}/request_bodies_ref`)
.set('content-type', 'text/html')
.set('accept', 'text/html')
.send(stringData)
.expect(200)
.then(r => {
expect(r.text).equals(stringData);
});
});

it('should return 200 if application/ld+json request body is satisfied by application/*', async () => {
request(app)
.post(`${app.basePath}/request_bodies_ref`)
.set('accept', 'application/ld+json')
.set('content-type', 'application/ld+json')
.send({
testProperty: 'abc',
})
.expect(200)
.then(r => {
const { body } = r;
expect(r.get('content-type')).to.contain('application/ld+json')
expect(body).to.have.property('testProperty');
});
});

it.only('should return 200 if application/vnd.api+json; type=two request body is validated agains the corrent schema', async () => {
request(app)
.post(`${app.basePath}/request_bodies_ref`)
.set('accept', 'application/vnd.api+json; type=two')
.set('content-type', 'application/vnd.api+json; type=two')
.send({
testPropertyTwo: 'abc',
})
.expect(200)
.then(r => {
const { body } = r;
expect(r.get('content-type')).to.contain('application/vnd.api+json; type=two')
expect(body).to.have.property('testPropertyTwo');
});
});

it('should return 400 if testProperty body property is not provided', async () =>
request(app)
.post(`${app.basePath}/request_bodies_ref`)
Expand Down
39 changes: 37 additions & 2 deletions test/resources/request.bodies.ref.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@ paths:
application/hal+json:
schema:
$ref: '#/components/schemas/Test'
'application/vnd.api+json; type=one':
schema:
$ref: '#/components/schemas/Test'
'application/vnd.api+json; type=two':
schema:
$ref: '#/components/schemas/TestTwo'
application/*:
schema:
$ref: '#/components/schemas/Test'
'*/*':
schema:
type: string

'400':
description: Bad Request

Expand All @@ -40,17 +53,39 @@ components:
format: phone-number
required:
- testProperty
TestTwo:
type: object
additionalProperties: false
properties:
testPropertyTwo:
type: string
example: +15017122661
format: phone-number
required:
- testPropertyTwo

requestBodies:
TestBody:
required: true
content:
text/plain:
schema:
type: string
schema:
type: string
application/json:
schema:
$ref: '#/components/schemas/Test'
application/hal+json:
schema:
$ref: '#/components/schemas/Test'
'application/vnd.api+json; type=one':
schema:
$ref: '#/components/schemas/Test'
'application/vnd.api+json; type=two':
schema:
$ref: '#/components/schemas/TestTwo'
application/*:
schema:
$ref: '#/components/schemas/Test'
'*/*':
schema:
type: string

0 comments on commit 446fad9

Please sign in to comment.