Skip to content

Commit

Permalink
colocate req/param parser
Browse files Browse the repository at this point in the history
  • Loading branch information
Carmine DiMascio committed Dec 29, 2019
1 parent f1b56e4 commit b300058
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 36 deletions.
20 changes: 18 additions & 2 deletions src/framework/types.ts
Expand Up @@ -2,6 +2,22 @@ import ajv = require('ajv');
import { Request, Response, NextFunction } from 'express';
export { OpenAPIFrameworkArgs };

export type BodySchema =
| OpenAPIV3.ReferenceObject
| OpenAPIV3.SchemaObject
| {};

export interface ParametersSchema {
query: object;
headers: object;
params: object;
cookies: object;
}

export interface ValidationSchema extends ParametersSchema {
body: BodySchema;
}

export interface OpenAPIFrameworkInit {
apiDoc: OpenAPIV3.Document;
basePaths: string[];
Expand Down Expand Up @@ -41,7 +57,7 @@ export interface OpenApiValidatorOpts {
unknownFormats?: true | string[] | 'ignore';
multerOpts?: {};
$refParser?: {
mode: 'bundle' | 'dereference',
mode: 'bundle' | 'dereference';
};
}

Expand Down Expand Up @@ -363,7 +379,7 @@ interface OpenAPIFrameworkArgs {
apiDoc: OpenAPIV3.Document | string;
validateApiDoc?: boolean;
$refParser?: {
mode: 'bundle' | 'dereference',
mode: 'bundle' | 'dereference';
};
}

Expand Down
14 changes: 7 additions & 7 deletions src/middlewares/openapi.request.validator.ts
Expand Up @@ -9,6 +9,7 @@ import {
import ono from 'ono';
import { NextFunction, RequestHandler, Response } from 'express';
import {
ValidationSchema,
OpenAPIV3,
OpenApiRequest,
RequestValidatorOptions,
Expand Down Expand Up @@ -82,18 +83,18 @@ export class RequestValidator {
): RequestHandler {
const apiDoc = this.apiDoc;
const schemaParser = new ParametersSchemaParser(apiDoc);
const parametersSchema = schemaParser.parse(path, reqSchema.parameters);
const securityQueryParam = Security.queryParam(apiDoc, reqSchema);
const bodySchemaParser = new BodySchemaParser(this.ajv, apiDoc);

// TODO bodyParser.parse should return OpenAPIV3.SchemaObject instead of BodySchema
const parameters = schemaParser.parse(path, reqSchema.parameters);
const securityQueryParam = Security.queryParam(apiDoc, reqSchema);
const body = bodySchemaParser.parse(path, reqSchema, contentType);

const properties: ValidationSchema = { ...parameters, body: body };
const required = (<SchemaObject>body).required ? ['body'] : [];

// $schema: "http://json-schema.org/draft-04/schema#",
const schema = {
required: ['query', 'headers', 'params'].concat(required),
properties: { ...parametersSchema, body: body },
properties,
};

const validator = this.ajv.compile(schema);
Expand All @@ -106,8 +107,7 @@ export class RequestValidator {
req.params = openapi.pathParams ?? req.params;
}

const parameters = reqSchema.parameters;
const mutator = new RequestParameterMutator(apiDoc, path, parameters);
const mutator = new RequestParameterMutator(apiDoc, path, properties);

mutator.modifyRequest(req);

Expand Down
7 changes: 1 addition & 6 deletions src/middlewares/parsers/body.parse.ts
@@ -1,12 +1,7 @@
import { Ajv } from 'ajv';
import { ContentType, validationError } from '../util';

import { OpenAPIV3 } from '../../framework/types';

export type BodySchema =
| OpenAPIV3.ReferenceObject
| OpenAPIV3.SchemaObject
| {};
import { OpenAPIV3, BodySchema } from '../../framework/types';

export class BodySchemaParser {
private _apiDoc: OpenAPIV3.Document;
Expand Down
31 changes: 18 additions & 13 deletions src/middlewares/parsers/req.parameter.mutator.ts
@@ -1,5 +1,10 @@
import { Request } from 'express';
import { OpenAPIV3 } from '../../framework/types';
import {
OpenAPIV3,
OpenApiRequest,
OpenApiRequestMetadata,
ValidationSchema,
} from '../../framework/types';
import { validationError } from '../util';
import { dereferenceParameter, normalizeParameter } from './util';
import * as mediaTypeParser from 'media-typer';
Expand Down Expand Up @@ -31,26 +36,27 @@ type Parameter = ReferenceObject | ParameterObject;
*/
export class RequestParameterMutator {
private _apiDocs: OpenAPIV3.Document;
private parameters: Parameter[];
private path: string;
private parsedSchema: ValidationSchema;

constructor(
apiDocs: OpenAPIV3.Document,
path: string,
parameters: Parameter[] = [],
parsedSchema: ValidationSchema,
) {
this._apiDocs = apiDocs;
this.path = path;
this.parameters = parameters;
this.parsedSchema = parsedSchema;
}

/**
* Modifies an incoing request object by applying the openapi schema
* req values may be parsed/mutated as a JSON object, JSON Exploded Object, JSON Array, or JSON Exploded Array
* @param req
*/
public modifyRequest(req: Request): void {
this.parameters.forEach(p => {
public modifyRequest(req: OpenApiRequest): void {
const { parameters } = (<OpenApiRequestMetadata>req.openapi).schema;
parameters.forEach(p => {
const parameter = dereferenceParameter(this._apiDocs, p);
const { name, schema } = normalizeParameter(parameter);
const { type } = <SchemaObject>schema;
Expand Down Expand Up @@ -195,13 +201,12 @@ export class RequestParameterMutator {
req[field][name] = {};
properties.forEach(property => {
if (req[field][property]) {
// const type = schema.properties[field].properties[name]
// .properties?.[property]?.type;
// const value = req[field][property];
// const coercedValue =
// type === 'array' && !Array.isArray(value) ? [value] : value;
// req[field][name][property] = coercedValue;
req[field][name][property] = req[field][property];
const schema = this.parsedSchema[field];
const type = schema.properties[name].properties?.[property]?.type;
const value = req[field][property];
const coercedValue =
type === 'array' && !Array.isArray(value) ? [value] : value;
req[field][name][property] = coercedValue;
delete req[field][property];
}
});
Expand Down
9 changes: 1 addition & 8 deletions src/middlewares/parsers/schema.parse.ts
@@ -1,4 +1,4 @@
import { OpenAPIV3 } from '../../framework/types';
import { OpenAPIV3, ParametersSchema } from '../../framework/types';
import { validationError } from '../util';
import { dereferenceParameter, normalizeParameter } from './util';

Expand All @@ -11,13 +11,6 @@ const PARAM_TYPE = {

type Parameter = OpenAPIV3.ReferenceObject | OpenAPIV3.ParameterObject;

export interface ParametersSchema {
query: object;
headers: object;
params: object;
cookies: object;
}

/**
* A class top arse incoing parameters and populate a list of request fields e.g. id and field types e.g. query
* whose value must later be parsed as a JSON object, JSON Exploded Object, JSON Array, or JSON Exploded Array
Expand Down

0 comments on commit b300058

Please sign in to comment.