Skip to content

Commit

Permalink
extract utilies
Browse files Browse the repository at this point in the history
  • Loading branch information
Carmine DiMascio committed Dec 29, 2019
1 parent 41a7407 commit f1b56e4
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 102 deletions.
72 changes: 8 additions & 64 deletions src/middlewares/parsers/req.parameter.mutator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Request } from 'express';
import { OpenAPIV3 } from '../../framework/types';
import { validationError } from '../util';
import { dereferenceParameter, normalizeParameter } from './util';
import * as mediaTypeParser from 'media-typer';
import * as contentTypeParser from 'content-type';

Expand Down Expand Up @@ -50,26 +51,21 @@ export class RequestParameterMutator {
*/
public modifyRequest(req: Request): void {
this.parameters.forEach(p => {
const parameter = Util.is$Ref(p)
? Util.dereference(this._apiDocs, <ReferenceObject>p)
: <ParameterObject>p;

Validate.parameterType(this.path, parameter);

const { name, schema } = Util.normalize(parameter);
const parameter = dereferenceParameter(this._apiDocs, p);
const { name, schema } = normalizeParameter(parameter);
const { type } = <SchemaObject>schema;
const { style, explode } = parameter;

if (parameter.content) {
this.handleContent(req, name, parameter);
} else if (parameter.in === 'query' && Util.isObjectOrXOf(schema)) {
} else if (parameter.in === 'query' && this.isObjectOrXOf(schema)) {
this.parseJsonAndMutateRequest(req, parameter.in, name);
if (style === 'form' && explode) {
this.handleFormExplode(req, name, <SchemaObject>schema, parameter);
}
} else if (type === 'array' && !explode) {
const delimiter = ARRAY_DELIMITER[parameter.style];
Validate.arrayDelimiter(this.path, delimiter, parameter);
this.validateArrayDelimiter(delimiter, parameter);
this.parseJsonArrayAndMutateRequest(req, parameter.in, name, delimiter);
} else if (type === 'array' && explode) {
this.explodeJsonArrayAndMutateRequest(req, parameter.in, name);
Expand Down Expand Up @@ -227,38 +223,8 @@ export class RequestParameterMutator {
req[field][name] = value;
}
}
}

class Util {
public static is$Ref(parameter: Parameter): boolean {
return parameter.hasOwnProperty('$ref');
}
public static dereference(
apiDocs: OpenAPIV3.Document,
parameter: ReferenceObject,
): ParameterObject {
const id = parameter.$ref.replace(/^.+\//i, '');
// TODO use ajv.getSchema. double nested $ref may later fail
return <ParameterObject>apiDocs.components.parameters[id];
}

public static normalize(
parameter: ParameterObject,
): {
name: string;
schema: Schema;
} {
let schema = parameter.schema;
if (!schema) {
const contentType = Object.keys(parameter.content)[0];
schema = parameter.content?.[contentType]?.schema;
}
const name =
parameter.in === 'header' ? parameter.name.toLowerCase() : parameter.name;
return { name, schema };
}

public static isObjectOrXOf(schema: Schema): boolean {
private isObjectOrXOf(schema: Schema): boolean {
const schemaHasObject = schema => {
if (!schema) return false;
const { type, allOf, oneOf, anyOf } = schema;
Expand All @@ -269,36 +235,14 @@ class Util {
};
return schemaHasObject(schema);
}
}

class Validate {
public static parameterType(path: string, parameter: ParameterObject): void {
const isKnownType = REQUEST_FIELDS[parameter.in];
if (!isKnownType) {
const message = `Parameter 'in' has incorrect value '${parameter.in}' for [${parameter.name}]`;
throw validationError(400, path, message);
}

const hasSchema = () => {
const contentType =
parameter.content && Object.keys(parameter.content)[0];
return !parameter.schema || !parameter.content?.[contentType]?.schema;
};

if (!hasSchema()) {
const message = `No available parameter in 'schema' or 'content' for [${parameter.name}]`;
throw validationError(400, path, message);
}
}

public static arrayDelimiter(
path: string,
private validateArrayDelimiter(
delimiter: string,
parameter: ParameterObject,
): void {
if (!delimiter) {
const message = `Parameter 'style' has incorrect value '${parameter.style}' for [${parameter.name}]`;
throw validationError(400, path, message);
throw validationError(400, this.path, message);
}
}
}
43 changes: 5 additions & 38 deletions src/middlewares/parsers/schema.parse.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { OpenAPIV3 } from '../../framework/types';
import { validationError } from '../util';
import { dereferenceParameter, normalizeParameter } from './util';

const PARAM_TYPE = {
query: 'query',
Expand All @@ -8,7 +9,6 @@ const PARAM_TYPE = {
cookie: 'cookies',
};

type Schema = OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject;
type Parameter = OpenAPIV3.ReferenceObject | OpenAPIV3.ParameterObject;

export interface ParametersSchema {
Expand Down Expand Up @@ -39,14 +39,12 @@ export class ParametersSchemaParser {
const schemas = { query: {}, headers: {}, params: {}, cookies: {} };

parameters.forEach(p => {
const parameter = Util.is$Ref(p)
? Util.dereference(this._apiDocs, <OpenAPIV3.ReferenceObject>p)
: <OpenAPIV3.ParameterObject>p;
const parameter = dereferenceParameter(this._apiDocs, p);

Validate.parameterType(path, parameter);
this.validateParameterType(path, parameter);

const reqField = PARAM_TYPE[parameter.in];
const { name, schema } = Util.normalize(parameter);
const { name, schema } = normalizeParameter(parameter);

if (!schemas[reqField].properties) {
schemas[reqField] = {
Expand All @@ -66,39 +64,8 @@ export class ParametersSchemaParser {

return schemas;
}
}
class Util {
public static is$Ref(parameter: Parameter): boolean {
return parameter.hasOwnProperty('$ref');
}
public static dereference(
apiDocs: OpenAPIV3.Document,
parameter: OpenAPIV3.ReferenceObject,
): OpenAPIV3.ParameterObject {
const id = parameter.$ref.replace(/^.+\//i, '');
// TODO use ajv.getSchema. double nested $ref may later fail
return <OpenAPIV3.ParameterObject>apiDocs.components.parameters[id];
}

public static normalize(
parameter: OpenAPIV3.ParameterObject,
): {
name: string;
schema: Schema;
} {
let schema = parameter.schema;
if (!schema) {
const contentType = Object.keys(parameter.content)[0];
schema = parameter.content?.[contentType]?.schema;
}
const name =
parameter.in === 'header' ? parameter.name.toLowerCase() : parameter.name;
return { name, schema };
}
}

class Validate {
public static parameterType(
private validateParameterType(
path: string,
parameter: OpenAPIV3.ParameterObject,
): void {
Expand Down
40 changes: 40 additions & 0 deletions src/middlewares/parsers/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { OpenAPIV3 } from '../../framework/types';

export function dereferenceParameter(
apiDocs: OpenAPIV3.Document,
parameter: OpenAPIV3.ReferenceObject | OpenAPIV3.ParameterObject,
): OpenAPIV3.ParameterObject {
// TODO this should recurse or use ajv.getSchema - if implemented as such, may want to cache the result
// as it is called by query.paraer and req.parameter mutator
if (is$Ref(parameter)) {
const p = <OpenAPIV3.ReferenceObject>parameter;
const id = p.$ref.replace(/^.+\//i, '');
return <OpenAPIV3.ParameterObject>apiDocs.components.parameters[id];
} else {
return <OpenAPIV3.ParameterObject>parameter;
}
}

export function normalizeParameter(
parameter: OpenAPIV3.ParameterObject,
): {
name: string;
schema: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject;
} {
// TODO this should recurse or use ajv.getSchema - if implemented as such, may want to cache the result
// as it is called by query.paraer and req.parameter mutator
let schema = parameter.schema;
if (!schema) {
const contentType = Object.keys(parameter.content)[0];
schema = parameter.content?.[contentType]?.schema;
}
const name =
parameter.in === 'header' ? parameter.name.toLowerCase() : parameter.name;
return { name, schema };
}

function is$Ref(
parameter: OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject,
): boolean {
return parameter.hasOwnProperty('$ref');
}

0 comments on commit f1b56e4

Please sign in to comment.