Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

express-openapi-validator

Package Overview
Dependencies
Maintainers
1
Versions
281
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

express-openapi-validator - npm Package Compare versions

Comparing version 4.13.7 to 4.14.0-beta.1

30

dist/framework/ajv/formats.d.ts
export declare const formats: {
int32: {
validate: (i: any) => boolean;
type: string;
readonly int32: {
readonly validate: (i: number) => boolean;
readonly type: "number";
};
int64: {
validate: (i: any) => boolean;
type: string;
readonly int64: {
readonly validate: (i: number) => boolean;
readonly type: "number";
};
float: {
validate: (i: any) => boolean;
type: string;
readonly float: {
readonly validate: (i: number) => boolean;
readonly type: "number";
};
double: {
validate: (i: any) => boolean;
type: string;
readonly double: {
readonly validate: (i: number) => boolean;
readonly type: "number";
};
byte: (b: any) => boolean;
binary: () => boolean;
password: () => boolean;
readonly byte: (b: string) => boolean;
readonly binary: () => boolean;
readonly password: () => boolean;
};

@@ -16,18 +16,21 @@ "use strict";

int32: {
validate: i => Number.isInteger(i) && i <= maxInt32 && i >= minInt32,
validate: (i) => Number.isInteger(i) && i <= maxInt32 && i >= minInt32,
type: 'number',
},
int64: {
validate: i => Number.isInteger(i) && i <= maxInt64 && i >= minInt64,
validate: (i) => Number.isInteger(i) && i <= maxInt64 && i >= minInt64,
type: 'number',
},
float: {
validate: i => typeof i === 'number' && (i === 0 || (i <= maxFloat && i >= minPosFloat) || (i >= minFloat && i <= maxNegFloat)),
validate: (i) => typeof i === 'number' &&
(i === 0 ||
(i <= maxFloat && i >= minPosFloat) ||
(i >= minFloat && i <= maxNegFloat)),
type: 'number',
},
double: {
validate: i => typeof i === 'number',
validate: (i) => typeof i === 'number',
type: 'number',
},
byte: b => b.length % 4 === 0 && base64regExp.test(b),
byte: (b) => b.length % 4 === 0 && base64regExp.test(b),
binary: alwaysTrue,

@@ -34,0 +37,0 @@ password: alwaysTrue,

@@ -1,4 +0,4 @@

import * as Ajv from 'ajv';
import AjvDraft4 from 'ajv-draft-04';
import { OpenAPIV3, Options } from '../types';
export declare function createRequestAjv(openApiSpec: OpenAPIV3.Document, options?: Options): Ajv.Ajv;
export declare function createResponseAjv(openApiSpec: OpenAPIV3.Document, options?: Options): Ajv.Ajv;
export declare function createRequestAjv(openApiSpec: OpenAPIV3.Document, options?: Options): AjvDraft4;
export declare function createResponseAjv(openApiSpec: OpenAPIV3.Document, options?: Options): AjvDraft4;
"use strict";
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createResponseAjv = exports.createRequestAjv = void 0;
const Ajv = require("ajv");
const draftSchema = require("ajv/lib/refs/json-schema-draft-04.json");
const ajv_draft_04_1 = require("ajv-draft-04");
const type_1 = require("ajv/dist/vocabularies/jtd/type");
const ajv_formats_1 = require("ajv-formats");
const formats_1 = require("./formats");

@@ -17,69 +29,87 @@ function createRequestAjv(openApiSpec, options = {}) {

var _a;
const ajv = new Ajv(Object.assign(Object.assign({}, options), { schemaId: 'auto', allErrors: true, meta: draftSchema, formats: Object.assign(Object.assign({}, formats_1.formats), options.formats), unknownFormats: options.unknownFormats }));
const { ajvFormats } = options, ajvOptions = __rest(options, ["ajvFormats"]);
const ajv = new ajv_draft_04_1.default(Object.assign(Object.assign({}, ajvOptions), { allErrors: true, formats: formats_1.formats }));
// Formats will overwrite existing validation,
// so set in order of least->most important.
if (options.serDesMap) {
for (const serDesFormat of Object.keys(options.serDesMap)) {
ajv.addFormat(serDesFormat, true);
}
}
for (const [formatName, formatValidation] of Object.entries(formats_1.formats)) {
ajv.addFormat(formatName, formatValidation);
}
if (ajvFormats) {
(0, ajv_formats_1.default)(ajv, ajvFormats);
}
for (let [formatName, formatDefinition] of Object.entries(options.formats)) {
ajv.addFormat(formatName, formatDefinition);
}
ajv.removeKeyword('propertyNames');
ajv.removeKeyword('contains');
ajv.removeKeyword('const');
if (options.serDesMap) {
// Alias for `type` that can execute AFTER x-eov-res-serdes
// There is a `type` keyword which this is positioned "next to",
// as well as high-level type assertion that runs before any keywords.
ajv.addKeyword(Object.assign(Object.assign({}, type_1.default), { keyword: 'x-eov-type', before: 'type' }));
}
if (request) {
if (options.serDesMap) {
ajv.addKeyword('x-eov-serdes', {
ajv.addKeyword({
keyword: 'x-eov-req-serdes',
modifying: true,
compile: (sch) => {
if (sch) {
return function validate(data, path, obj, propName) {
if (!!sch.deserialize) {
if (typeof data !== 'string') {
validate.errors = [
{
keyword: 'serdes',
schemaPath: data,
dataPath: path,
message: `must be a string`,
params: { 'x-eov-serdes': propName },
},
];
return false;
}
try {
obj[propName] = sch.deserialize(data);
}
catch (e) {
validate.errors = [
{
keyword: 'serdes',
schemaPath: data,
dataPath: path,
message: `format is invalid`,
params: { 'x-eov-serdes': propName },
},
];
return false;
}
}
errors: true,
// Deserialization occurs AFTER all string validations
post: true,
compile: (sch, p, it) => {
const validate = (data, ctx) => {
if (typeof data !== 'string') {
// Either null (possibly allowed, defer to nullable validation)
// or already failed string validation (no need to throw additional internal errors).
return true;
};
}
return () => true;
}
try {
ctx.parentData[ctx.parentDataProperty] = sch.deserialize(data);
}
catch (e) {
validate.errors = [
{
keyword: 'serdes',
instancePath: ctx.instancePath,
schemaPath: it.schemaPath.str,
message: `format is invalid`,
params: { 'x-eov-req-serdes': ctx.parentDataProperty },
},
];
return false;
}
return true;
};
return validate;
},
// errors: 'full',
});
}
ajv.removeKeyword('readOnly');
ajv.addKeyword('readOnly', {
modifying: true,
compile: (sch) => {
ajv.addKeyword({
keyword: 'readOnly',
errors: true,
compile: (sch, p, it) => {
if (sch) {
return function validate(data, path, obj, propName) {
const isValid = !(sch === true && data != null);
delete obj[propName];
validate.errors = [
{
keyword: 'readOnly',
schemaPath: data,
dataPath: path,
message: `is read-only`,
params: { readOnly: propName },
},
];
return isValid;
const validate = (data, ctx) => {
const isValid = data == null;
if (!isValid) {
validate.errors = [
{
keyword: 'readOnly',
instancePath: ctx.instancePath,
schemaPath: it.schemaPath.str,
message: `is read-only`,
params: { writeOnly: ctx.parentDataProperty },
},
];
}
return false;
};
return validate;
}

@@ -93,30 +123,30 @@ return () => true;

if (options.serDesMap) {
ajv.addKeyword('x-eov-serdes', {
ajv.addKeyword({
keyword: 'x-eov-res-serdes',
modifying: true,
compile: (sch) => {
if (sch) {
return function validate(data, path, obj, propName) {
if (typeof data === 'string')
return true;
if (!!sch.serialize) {
try {
obj[propName] = sch.serialize(data);
}
catch (e) {
validate.errors = [
{
keyword: 'serdes',
schemaPath: data,
dataPath: path,
message: `format is invalid`,
params: { 'x-eov-serdes': propName },
},
];
return false;
}
}
errors: true,
// Serialization occurs BEFORE type validations
before: 'x-eov-type',
compile: (sch, p, it) => {
const validate = (data, ctx) => {
if (typeof data === 'string')
return true;
};
}
return () => true;
try {
ctx.parentData[ctx.parentDataProperty] = sch.serialize(data);
}
catch (e) {
validate.errors = [
{
keyword: 'serdes',
instancePath: ctx.instancePath,
schemaPath: it.schemaPath.str,
message: `format is invalid`,
params: { 'x-eov-res-serdes': ctx.parentDataProperty },
},
];
return false;
}
return true;
};
return validate;
},

@@ -126,19 +156,24 @@ });

ajv.removeKeyword('writeOnly');
ajv.addKeyword('writeOnly', {
modifying: true,
compile: (sch) => {
ajv.addKeyword({
keyword: 'writeOnly',
schemaType: 'boolean',
errors: true,
compile: (sch, p, it) => {
if (sch) {
return function validate(data, path, obj, propName) {
const isValid = !(sch === true && data != null);
validate.errors = [
{
keyword: 'writeOnly',
dataPath: path,
schemaPath: path,
message: `is write-only`,
params: { writeOnly: propName },
},
];
return isValid;
const validate = (data, ctx) => {
const isValid = data == null;
if (!isValid) {
validate.errors = [
{
keyword: 'writeOnly',
instancePath: ctx.instancePath,
schemaPath: it.schemaPath.str,
message: `is write-only`,
params: { writeOnly: ctx.parentDataProperty },
},
];
}
return false;
};
return validate;
}

@@ -145,0 +180,0 @@ return () => true;

@@ -1,8 +0,7 @@

import ajv = require('ajv');
import { OpenApiValidatorOpts, Options, RequestValidatorOptions } from '../types';
import { NormalizedOpenApiValidatorOpts, Options, RequestValidatorOptions } from '../types';
export declare class AjvOptions {
private options;
constructor(options: OpenApiValidatorOpts);
get preprocessor(): ajv.Options;
get response(): ajv.Options;
constructor(options: NormalizedOpenApiValidatorOpts);
get preprocessor(): Options;
get response(): Options;
get request(): RequestValidatorOptions;

@@ -9,0 +8,0 @@ get multipart(): Options;

@@ -26,3 +26,3 @@ "use strict";

baseOptions() {
const { coerceTypes, unknownFormats, validateFormats, serDes, } = this.options;
const { coerceTypes, formats, validateFormats, serDes, ajvFormats } = this.options;
const serDesMap = {};

@@ -42,19 +42,17 @@ for (const serDesObject of serDes) {

}
return {
const options = {
strict: false,
strictNumbers: true,
strictTuples: true,
allowUnionTypes: false,
validateSchema: false,
nullable: true,
coerceTypes,
useDefaults: true,
removeAdditional: false,
unknownFormats,
format: validateFormats,
formats: this.options.formats.reduce((acc, f) => {
acc[f.name] = {
type: f.type,
validate: f.validate,
};
return acc;
}, {}),
serDesMap: serDesMap,
validateFormats: validateFormats,
formats,
serDesMap,
ajvFormats,
};
return options;
}

@@ -61,0 +59,0 @@ }

@@ -1,2 +0,2 @@

import * as Ajv from 'ajv';
import { ErrorObject } from 'ajv-draft-04';
import { OpenAPIV3 } from './types.js';

@@ -12,4 +12,4 @@ export interface OpenAPISchemaValidatorOpts {

validate(openapiDoc: OpenAPIV3.Document): {
errors: Array<Ajv.ErrorObject> | null;
errors: Array<ErrorObject> | null;
};
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpenAPISchemaValidator = void 0;
const Ajv = require("ajv");
const draftSchema = require("ajv/lib/refs/json-schema-draft-04.json");
const ajv_draft_04_1 = require("ajv-draft-04");
const ajv_formats_1 = require("ajv-formats");
// https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v3.0/schema.json

@@ -11,4 +11,9 @@ const openapi3Schema = require("./openapi.v3.schema.json");

const options = {
schemaId: 'auto',
schemaId: 'id',
allErrors: true,
validateFormats: true,
coerceTypes: false,
useDefaults: false,
// Strict enforcement is nice, but schema is controlled by this library and known to be valid
strict: false,
};

@@ -18,4 +23,4 @@ if (!opts.validateApiSpec) {

}
const v = new Ajv(options);
v.addMetaSchema(draftSchema);
const v = new ajv_draft_04_1.default(options);
(0, ajv_formats_1.default)(v, ['email', 'regex', 'uri', 'uri-reference']);
const ver = opts.version && parseInt(String(opts.version), 10);

@@ -22,0 +27,0 @@ if (!ver)

@@ -76,3 +76,3 @@ "use strict";

// /{path}* => /:path*)
// /{path}(*) => /:path*)
// /{path}(*) => /:path*)
const pass1 = part.replace(/\/{([^\*]+)}\({0,1}(\*)\){0,1}/g, '/:$1$2');

@@ -79,0 +79,0 @@ // substitute params with express equivalent

import * as ajv from 'ajv';
import * as multer from 'multer';
import { FormatsPluginOptions } from 'ajv-formats';
import { Request, Response, NextFunction } from 'express';

@@ -28,2 +29,3 @@ export { OpenAPIFrameworkArgs };

serDesMap?: SerDesMap;
ajvFormats?: FormatsPluginOptions;
}

@@ -56,3 +58,2 @@ export interface RequestValidatorOptions extends Options, ValidateRequestOpts {

format: string;
jsonType?: string;
serialize?: (o: unknown) => string;

@@ -65,3 +66,2 @@ deserialize?: (s: string) => unknown;

format: string;
jsonType: string;
serialize?: (o: unknown) => string;

@@ -71,3 +71,2 @@ deserialize?: (s: string) => unknown;

format: string;
jsonType?: string;
serialize: (o: unknown) => string;

@@ -90,5 +89,10 @@ deserialize: (s: string) => unknown;

coerceTypes?: boolean | 'array';
/**
* @deprecated
* Use `formats` + `validateFormats` to ignore specified formats
*/
unknownFormats?: true | string[] | 'ignore';
serDes?: SerDes[];
formats?: Format[];
formats?: Format[] | Record<string, ajv.Format>;
ajvFormats?: FormatsPluginOptions;
fileUploader?: boolean | multer.Options;

@@ -100,4 +104,18 @@ multerOpts?: multer.Options;

operationHandlers?: false | string | OperationHandlerOptions;
validateFormats?: false | 'fast' | 'full';
validateFormats?: boolean | 'fast' | 'full';
}
export interface NormalizedOpenApiValidatorOpts extends OpenApiValidatorOpts {
validateApiSpec: boolean;
validateResponses: false | ValidateResponseOpts;
validateRequests: false | ValidateRequestOpts;
validateSecurity: false | ValidateSecurityOpts;
fileUploader: boolean | multer.Options;
$refParser: {
mode: 'bundle' | 'dereference';
};
operationHandlers: false | OperationHandlerOptions;
formats: Record<string, ajv.Format>;
validateFormats: boolean;
unknownFormats?: never;
}
export declare namespace OpenAPIV3 {

@@ -104,0 +122,0 @@ export interface Document {

@@ -7,3 +7,2 @@ "use strict";

this.format = param.format;
this.jsonType = param.jsonType || 'object';
this.serialize = param.serialize;

@@ -13,9 +12,7 @@ this.deserialize = param.deserialize;

format: param.format,
jsonType: param.jsonType || 'object',
deserialize: param.deserialize
deserialize: param.deserialize,
};
this.serializer = {
format: param.format,
jsonType: param.jsonType || 'object',
serialize: param.serialize
serialize: param.serialize,
};

@@ -22,0 +19,0 @@ }

@@ -11,2 +11,3 @@ import { NextFunction, Response } from 'express';

validate(req: OpenApiRequest, res: Response, next: NextFunction): void;
private warnUnknownQueryParametersKeyword;
private buildMiddleware;

@@ -13,0 +14,0 @@ private discriminatorValidator;

@@ -43,2 +43,9 @@ "use strict";

}
warnUnknownQueryParametersKeyword(reqSchema) {
var _a;
if (typeof reqSchema['x-allow-unknown-query-parameters'] === 'boolean') {
console.warn('"x-allow-unknown-query-parameters" is deprecated. Use "x-eov-allow-unknown-query-parameters"');
}
return ((_a = reqSchema['x-allow-unknown-query-parameters']) !== null && _a !== void 0 ? _a : this.requestOpts.allowUnknownQueryParameters);
}
buildMiddleware(path, reqSchema, contentType) {

@@ -55,3 +62,3 @@ var _a;

});
const allowUnknownQueryParameters = !!((_a = reqSchema['x-allow-unknown-query-parameters']) !== null && _a !== void 0 ? _a : this.requestOpts.allowUnknownQueryParameters);
const allowUnknownQueryParameters = !!((_a = reqSchema['x-eov-allow-unknown-query-parameters']) !== null && _a !== void 0 ? _a : this.warnUnknownQueryParametersKeyword(reqSchema));
return (req, res, next) => {

@@ -126,3 +133,3 @@ var _a, _b, _c, _d, _e, _f;

path: req.path,
message: `'${property}' should be equal to one of the allowed values: ${options
message: `'${property}' must be equal to one of the allowed values: ${options
.map((o) => o.option)

@@ -153,3 +160,3 @@ .join(', ')}.`,

throw new types_1.BadRequest({
path: `.query.${q}`,
path: `/query/${q}`,
message: `Unknown query parameter '${q}'`,

@@ -160,3 +167,3 @@ });

throw new types_1.BadRequest({
path: `.query.${q}`,
path: `/query/${q}`,
message: `Empty value found for query parameter '${q}'`,

@@ -163,0 +170,0 @@ });

import { RequestHandler } from 'express';
import * as ajv from 'ajv';
import { ValidateFunction, Options } from 'ajv';
import { OpenAPIV3, OpenApiRequest, ValidateResponseOpts } from '../framework/types';
interface ValidateResult {
validators: {
[key: string]: ajv.ValidateFunction;
[key: string]: ValidateFunction;
};

@@ -18,6 +18,6 @@ body: object;

private eovOptions;
constructor(openApiSpec: OpenAPIV3.Document, options?: ajv.Options, eovOptions?: ValidateResponseOpts);
constructor(openApiSpec: OpenAPIV3.Document, options?: Options, eovOptions?: ValidateResponseOpts);
validate(): RequestHandler;
_getOrBuildValidator(req: OpenApiRequest, responses: OpenAPIV3.ResponsesObject): {
[key: string]: ajv.ValidateFunction;
[key: string]: ValidateFunction;
};

@@ -24,0 +24,0 @@ _validate({ validators, body, statusCode, path, accepts, }: ValidateResult): void;

@@ -111,3 +111,3 @@ "use strict";

throw new types_1.InternalServerError({
path: '.response',
path: '/response',
message: 'response should NOT have a body',

@@ -132,3 +132,3 @@ });

throw new types_1.InternalServerError({
path: '.response',
path: '/response',
message: 'response body required.',

@@ -135,0 +135,0 @@ });

@@ -1,2 +0,2 @@

import { Ajv } from 'ajv';
import Ajv from 'ajv';
import { OpenAPIV3, OpenApiRequest, ValidationSchema } from '../../framework/types';

@@ -3,0 +3,0 @@ /**

@@ -268,3 +268,3 @@ "use strict";

const message = `Parameter '${name}' must be url encoded. Its value may not contain reserved characters.`;
throw new types_1.BadRequest({ path: `.query.${name}`, message: message });
throw new types_1.BadRequest({ path: `/query/${name}`, message: message });
}

@@ -271,0 +271,0 @@ }

import { OpenAPIV3, ParametersSchema } from '../../framework/types';
import { Ajv } from 'ajv';
import Ajv from 'ajv';
declare type Parameter = OpenAPIV3.ReferenceObject | OpenAPIV3.ParameterObject;

@@ -4,0 +4,0 @@ /**

@@ -24,2 +24,34 @@ import { OpenAPIV3, Options, ValidateResponseOpts } from '../../framework/types';

private processDiscriminator;
/**
* Attach custom `x-eov-*-serdes` vendor extension for performing
* serialization (response) and deserialization (request) of data.
*
* This only applies to `type=string` schemas with a `format` that was flagged for serdes.
*
* The goal of this function is to define a JSON schema that:
* 1) Only performs the method for matching req/res (e.g. never deserialize a response)
* 2) Validates initial data THEN performs serdes THEN validates output. In that order.
* 3) Hide internal schema keywords (and its validation errors) from user.
*
* The solution is in three parts:
* 1) Remove the `type` keywords and replace it with a custom clone `x-eov-type`.
* This ensures that we control the order of type validations,
* and allows the response serialization to occur before AJV enforces the type.
* 2) Add an `x-eov-req-serdes` keyword.
* This keyword will deserialize the request string AFTER all other validations occur,
* ensuring that the string is valid before modifications.
* This keyword is only attached when deserialization is enabled.
* 3) Add an `x-eov-res-serdes` keyword.
* This keyword will serialize the response object BEFORE any other validations occur,
* ensuring the output is validated as a string.
* This keyword is only attached when serialization is enabled.
* 4) If `nullable` is set, set the type as every possible type.
* Then initial type checking will _always_ pass and the `x-eov-type` will narrow it down later.
*
* See [`createAjv`](../../framework/ajv/index.ts) for custom keyword definitions.
*
* @param {object} parent - parent schema
* @param {object} schema - schema
* @param {object} state - traversal state
*/
private handleSerDes;

@@ -26,0 +58,0 @@ private handleReadonly;

@@ -232,6 +232,10 @@ "use strict";

}
(_p = ancestor._discriminator) !== null && _p !== void 0 ? _p : (ancestor._discriminator = {
validators: {},
options: o.options,
property: o.discriminator,
// Expose `_discriminator` to consumers without exposing to AJV
Object.defineProperty(ancestor, '_discriminator', {
enumerable: false,
value: (_p = ancestor._discriminator) !== null && _p !== void 0 ? _p : {
validators: {},
options: o.options,
property: o.discriminator,
},
});

@@ -248,2 +252,34 @@ for (const option of options) {

}
/**
* Attach custom `x-eov-*-serdes` vendor extension for performing
* serialization (response) and deserialization (request) of data.
*
* This only applies to `type=string` schemas with a `format` that was flagged for serdes.
*
* The goal of this function is to define a JSON schema that:
* 1) Only performs the method for matching req/res (e.g. never deserialize a response)
* 2) Validates initial data THEN performs serdes THEN validates output. In that order.
* 3) Hide internal schema keywords (and its validation errors) from user.
*
* The solution is in three parts:
* 1) Remove the `type` keywords and replace it with a custom clone `x-eov-type`.
* This ensures that we control the order of type validations,
* and allows the response serialization to occur before AJV enforces the type.
* 2) Add an `x-eov-req-serdes` keyword.
* This keyword will deserialize the request string AFTER all other validations occur,
* ensuring that the string is valid before modifications.
* This keyword is only attached when deserialization is enabled.
* 3) Add an `x-eov-res-serdes` keyword.
* This keyword will serialize the response object BEFORE any other validations occur,
* ensuring the output is validated as a string.
* This keyword is only attached when serialization is enabled.
* 4) If `nullable` is set, set the type as every possible type.
* Then initial type checking will _always_ pass and the `x-eov-type` will narrow it down later.
*
* See [`createAjv`](../../framework/ajv/index.ts) for custom keyword definitions.
*
* @param {object} parent - parent schema
* @param {object} schema - schema
* @param {object} state - traversal state
*/
handleSerDes(parent, schema, state) {

@@ -253,4 +289,17 @@ if (schema.type === 'string' &&

this.serDesMap[schema.format]) {
schema.type = [this.serDesMap[schema.format].jsonType || 'object', 'string'];
schema['x-eov-serdes'] = this.serDesMap[schema.format];
const serDes = this.serDesMap[schema.format];
schema['x-eov-type'] = schema.type;
if ('nullable' in schema) {
// Ajv requires `type` keyword with `nullable` (regardless of value).
schema.type = ['string', 'number', 'boolean', 'object', 'array'];
}
else {
delete schema.type;
}
if (serDes.deserialize) {
schema['x-eov-req-serdes'] = serDes;
}
if (serDes.serialize) {
schema['x-eov-res-serdes'] = serDes;
}
}

@@ -257,0 +306,0 @@ }

@@ -1,2 +0,2 @@

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

@@ -3,0 +3,0 @@ export declare function dereferenceParameter(apiDocs: OpenAPIV3.Document, parameter: OpenAPIV3.ReferenceObject | OpenAPIV3.ParameterObject): OpenAPIV3.ParameterObject;

@@ -1,2 +0,2 @@

import * as Ajv from 'ajv';
import type { ErrorObject } from 'ajv-draft-04';
import { Request } from 'express';

@@ -20,4 +20,4 @@ import { ValidationError } from '../framework/types';

*/
export declare function augmentAjvErrors(errors?: Ajv.ErrorObject[]): Ajv.ErrorObject[];
export declare function ajvErrorsToValidatorError(status: number, errors: Ajv.ErrorObject[]): ValidationError;
export declare function augmentAjvErrors(errors?: ErrorObject[]): ErrorObject[];
export declare function ajvErrorsToValidatorError(status: number, errors: ErrorObject[]): ValidationError;
export declare const deprecationWarning: {

@@ -24,0 +24,0 @@ (...data: any[]): void;

@@ -13,3 +13,5 @@ "use strict";

if (contentType) {
this.withoutBoundary = contentType.replace(/;\s{0,}boundary.*/, '').toLowerCase();
this.withoutBoundary = contentType
.replace(/;\s{0,}boundary.*/, '')
.toLowerCase();
this.mediaType = this.withoutBoundary.split(';')[0].toLowerCase().trim();

@@ -54,3 +56,14 @@ this.charSet = (_a = this.withoutBoundary.split(';')[1]) === null || _a === void 0 ? void 0 : _a.toLowerCase();

});
return errors;
const serDesPaths = new Set();
return errors.filter((e) => {
if (serDesPaths.has(e.schemaPath)) {
return false;
}
if (e.params['x-eov-res-serdes']) {
// If response serialization failed,
// silence additional errors about not being a string.
serDesPaths.add(e.schemaPath.replace('x-eov-res-serdes', 'x-eov-type'));
}
return true;
});
}

@@ -64,6 +77,7 @@ exports.augmentAjvErrors = augmentAjvErrors;

const params = e.params;
const required = (params === null || params === void 0 ? void 0 : params.missingProperty) && e.dataPath + '.' + params.missingProperty;
const required = (params === null || params === void 0 ? void 0 : params.missingProperty) &&
e.instancePath + '/' + params.missingProperty;
const additionalProperty = (params === null || params === void 0 ? void 0 : params.additionalProperty) &&
e.dataPath + '.' + params.additionalProperty;
const path = (_b = (_a = required !== null && required !== void 0 ? required : additionalProperty) !== null && _a !== void 0 ? _a : e.dataPath) !== null && _b !== void 0 ? _b : e.schemaPath;
e.instancePath + '/' + params.additionalProperty;
const path = (_b = (_a = required !== null && required !== void 0 ? required : additionalProperty) !== null && _a !== void 0 ? _a : e.instancePath) !== null && _b !== void 0 ? _b : e.schemaPath;
return {

@@ -70,0 +84,0 @@ path,

import { Application, Router } from 'express';
import { OpenApiContext } from './framework/openapi.context';
import { Spec } from './framework/openapi.spec.loader';
import { OpenApiValidatorOpts, OpenApiRequestHandler } from './framework/types';
import { NormalizedOpenApiValidatorOpts, OpenApiValidatorOpts, OpenApiRequestHandler } from './framework/types';
import { AjvOptions } from './framework/ajv/options';
export { OpenApiValidatorOpts, InternalServerError, UnsupportedMediaType, RequestEntityTooLarge, BadRequest, MethodNotAllowed, NotAcceptable, NotFound, Unauthorized, Forbidden, } from './framework/types';
export declare class OpenApiValidator {
readonly options: OpenApiValidatorOpts;
readonly options: NormalizedOpenApiValidatorOpts;
readonly ajvOpts: AjvOptions;

@@ -10,0 +10,0 @@ constructor(options: OpenApiValidatorOpts);

@@ -25,4 +25,2 @@ "use strict";

constructor(options) {
this.validateOptions(options);
this.normalizeOptions(options);
if (options.validateApiSpec == null)

@@ -40,8 +38,6 @@ options.validateApiSpec = true;

options.$refParser = { mode: 'bundle' };
if (options.unknownFormats == null)
options.unknownFormats === true;
if (options.validateFormats == null)
options.validateFormats = 'fast';
options.validateFormats = true;
if (options.formats == null)
options.formats = [];
options.formats = {};
if (typeof options.operationHandlers === 'string') {

@@ -78,4 +74,5 @@ /**

}
this.options = options;
this.ajvOpts = new options_1.AjvOptions(options);
this.validateOptions(options);
this.options = this.normalizeOptions(options);
this.ajvOpts = new options_1.AjvOptions(this.options);
}

@@ -280,13 +277,35 @@ installMiddleware(spec) {

const unknownFormats = options.unknownFormats;
if (typeof unknownFormats === 'boolean') {
if (!unknownFormats) {
if (unknownFormats !== undefined) {
if (typeof unknownFormats === 'boolean') {
if (!unknownFormats) {
throw (0, ono_1.default)("unknownFormats must contain an array of unknownFormats, 'ignore' or true");
}
}
else if (typeof unknownFormats === 'string' &&
unknownFormats !== 'ignore' &&
!Array.isArray(unknownFormats))
throw (0, ono_1.default)("unknownFormats must contain an array of unknownFormats, 'ignore' or true");
}
console.warn('unknownFormats is deprecated.');
}
else if (typeof unknownFormats === 'string' &&
unknownFormats !== 'ignore' &&
!Array.isArray(unknownFormats))
throw (0, ono_1.default)("unknownFormats must contain an array of unknownFormats, 'ignore' or true");
if (Array.isArray(options.formats)) {
console.warn('formats as an array is deprecated. Use object instead https://ajv.js.org/options.html#formats');
}
if (typeof options.validateFormats === 'string') {
console.warn(`"validateFormats" as a string is deprecated. Set to a boolean and use "ajvFormats"`);
}
}
normalizeOptions(options) {
if (Array.isArray(options.formats)) {
const formats = {};
for (const { name, type, validate } of options.formats) {
if (type) {
const formatValidator = { type, validate };
formats[name] = formatValidator;
}
else {
formats[name] = validate;
}
}
options.formats = formats;
}
if (!options.serDes) {

@@ -296,11 +315,2 @@ options.serDes = base_serdes_1.defaultSerDes;

else {
if (!Array.isArray(options.unknownFormats)) {
options.unknownFormats = Array();
}
options.serDes.forEach((currentSerDes) => {
if (options.unknownFormats.indexOf(currentSerDes.format) ===
-1) {
options.unknownFormats.push(currentSerDes.format);
}
});
base_serdes_1.defaultSerDes.forEach((currentDefaultSerDes) => {

@@ -315,2 +325,20 @@ let defaultSerDesOverride = options.serDes.find((currentOptionSerDes) => {

}
if (typeof options.validateFormats === 'string') {
if (!options.ajvFormats) {
options.ajvFormats = { mode: options.validateFormats };
}
options.validateFormats = true;
}
else if (options.validateFormats && !options.ajvFormats) {
options.ajvFormats = { mode: 'fast' };
}
if (Array.isArray(options.unknownFormats)) {
for (const format of options.unknownFormats) {
options.formats[format] = true;
}
}
else if (options.unknownFormats === 'ignore') {
options.validateFormats = false;
}
return options;
}

@@ -317,0 +345,0 @@ isOperationHandlerOptions(value) {

{
"name": "express-openapi-validator",
"version": "4.13.7",
"version": "4.14.0-beta.1",
"description": "Automatically validate API requests and responses with OpenAPI 3 and Express.",

@@ -36,3 +36,5 @@ "main": "dist/index.js",

"@types/multer": "^1.4.7",
"ajv": "^6.12.6",
"ajv": "^8.6.2",
"ajv-draft-04": "^1.0.0",
"ajv-formats": "^2.1.1",
"content-type": "^1.0.4",

@@ -39,0 +41,0 @@ "json-schema-ref-parser": "^9.0.9",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc