New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

open-api-mocker

Package Overview
Dependencies
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

open-api-mocker - npm Package Compare versions

Comparing version 1.7.0 to 1.7.1

lib/mocker/express/request-handler.js

8

CHANGELOG.md

@@ -9,2 +9,10 @@ # Changelog

## [1.7.1] - 2021-06-22
### Fixed
- Response header `x-powered-by` has now the correct value
- Schema Object `pattern` property can be passed as a string (#35)
- Refactor to improve code quality and maintainability (#37)
- Schemas with `oneOf`, `anyOf` and `allOf` now work properly and don't get wrong default values injected (#41)
- Dependencies updated to fix vulnerabilities
## [1.7.0] - 2021-04-20

@@ -11,0 +19,0 @@ ### Added

4

lib/components/parser.js

@@ -6,2 +6,3 @@ 'use strict';

const ComponentsStruct = require('./structs');
const extractExtensions = require('../utils/extract-extensions');

@@ -41,4 +42,3 @@ class Parser {

const extensionProps = Object.entries(otherProps)
.filter(([propName]) => propName.substr(0, 2) === 'x-');
const extensionProps = extractExtensions(otherProps);

@@ -45,0 +45,0 @@ return new Components({

@@ -8,2 +8,16 @@ 'use strict';

const optionalListOf = elementsStruct => struct.optional(struct.list([elementsStruct]));
const optionalUnionOf = validStructs => struct.optional(struct.union(validStructs));
const referenceUnion = otherStruct => struct.union([otherStruct, ReferenceStruct]);
const getDefaultType = ({ allOf, oneOf, anyOf }) => (allOf || oneOf || anyOf ? undefined : 'object');
const getDefaultTypeFlags = ({ type, allOf, oneOf, anyOf }) => {
const finalType = type || getDefaultType({ allOf, oneOf, anyOf });
return finalType ? false : undefined;
};
const SchemaStruct = struct.intersection([

@@ -20,3 +34,3 @@ 'object',

minLength: 'number?',
pattern: 'regexp?',
pattern: 'string|regexp?',
maxItems: 'number?',

@@ -28,38 +42,17 @@ minItems: 'number?',

required: struct.union(['boolean?', struct.optional(['string'])]),
enum: struct.optional(struct.list([struct.union(['string', 'number', 'boolean'])])),
enum: optionalListOf(struct.union(['string', 'number', 'boolean'])),
type: 'string?',
allOf: struct.lazy(() => struct.optional(struct.list([struct.union([
SchemaStruct,
ReferenceStruct
])]))),
oneOf: struct.lazy(() => struct.optional(struct.list([struct.union([
SchemaStruct,
ReferenceStruct
])]))),
anyOf: struct.lazy(() => struct.optional(struct.list([struct.union([
SchemaStruct,
ReferenceStruct
])]))),
not: struct.lazy(() => struct.optional(struct.union([
SchemaStruct,
ReferenceStruct
]))),
items: struct.lazy(() => struct.optional(struct.union([
SchemaStruct,
ReferenceStruct
]))),
properties: struct.lazy(() => struct.optional(struct.dict(['string', struct.union([
SchemaStruct,
ReferenceStruct
])]))),
additionalProperties: struct.optional(struct.union([
allOf: struct.lazy(() => optionalListOf(referenceUnion(SchemaStruct))),
oneOf: struct.lazy(() => optionalListOf(referenceUnion(SchemaStruct))),
anyOf: struct.lazy(() => optionalListOf(referenceUnion(SchemaStruct))),
not: struct.lazy(() => struct.optional(referenceUnion(SchemaStruct))),
items: struct.lazy(() => struct.optional(referenceUnion(SchemaStruct))),
properties: struct.lazy(() => struct.optional(struct.dict(['string', referenceUnion(SchemaStruct)]))),
additionalProperties: optionalUnionOf([
'boolean',
struct.lazy(() => struct.union([
SchemaStruct,
ReferenceStruct
]))
])),
struct.lazy(() => referenceUnion(SchemaStruct))
]),
description: 'string?',
format: 'string?',
default: struct.optional(struct.union(['string', 'number', 'boolean', 'object', 'array'])),
default: optionalUnionOf(['string', 'number', 'boolean', 'object', 'array']),
nullable: 'boolean?',

@@ -69,10 +62,10 @@ readOnly: 'boolean?',

externalDocs: ExternalDocsStruct,
example: struct.optional(struct.union(['string', 'number', 'boolean', 'object', 'array'])),
example: optionalUnionOf(['string', 'number', 'boolean', 'object', 'array']),
deprecated: 'boolean?'
}, {
type: 'object',
nullable: false,
readOnly: false,
writeOnly: false,
deprecated: false
type: getDefaultType,
nullable: getDefaultTypeFlags,
readOnly: getDefaultTypeFlags,
writeOnly: getDefaultTypeFlags,
deprecated: getDefaultTypeFlags
})

@@ -79,0 +72,0 @@ ]);

'use strict';
const ParserError = require('../errors/parser-error');
const ExternalDocumentation = require('./external-documentation');
const ExternalDocumentationsStruct = require('./structs');
const extractExtensions = require('../utils/extract-extensions');
const enhanceStructValidationError = require('../utils/enhance-struct-validation-error');

@@ -23,7 +24,3 @@ class Parser {

} catch(e) {
const path = e.path
.reduce((acum, pathPart) => `${acum}.${pathPart}`, 'externalDocs');
throw new ParserError(e.message, path);
throw enhanceStructValidationError(e, 'externalDocs');
}

@@ -34,4 +31,3 @@ }

const extensionProps = Object.entries(otherProps)
.filter(([propName]) => propName.substr(0, 2) === 'x-');
const extensionProps = extractExtensions(otherProps);

@@ -38,0 +34,0 @@ return new ExternalDocumentation({

@@ -6,2 +6,3 @@ 'use strict';

const InfoStruct = require('./structs');
const extractExtensions = require('../utils/extract-extensions');

@@ -36,4 +37,3 @@ class Parser {

const extensionProps = Object.entries(otherProps)
.filter(([propName]) => propName.substr(0, 2) === 'x-');
const extensionProps = extractExtensions(otherProps);

@@ -40,0 +40,0 @@ return new Info({

@@ -11,4 +11,3 @@ 'use strict';

const colors = require('colors');
const parsePreferHeader = require('parse-prefer-header');
const memoize = require('micro-memoize');
const handleRequest = require('./request-handler');

@@ -70,64 +69,29 @@ const openApiMockSymbol = Symbol('openApiMock');

this.paths.map(path => {
this.setRoutes(app);
logger.debug(`Processing schema path ${path.httpMethod.toUpperCase()} ${path.uri}`);
app.all('*', this._notFoundHandler.bind(this));
const expressHttpMethod = path.httpMethod.toLowerCase();
return this.startServer(app);
}
const uris = this._normalizeExpressPath(path.uri);
setRoutes(app) {
this.paths.map(path => this.setRoute(app, path));
}
// Create a function that is memoized using the URL, query, the Prefer header and the body.
// eslint-disable-next-line no-unused-vars
const getResponse = (url, query, preferHeader, body) => {
const { example: preferredExampleName, statuscode: preferredStatusCode } = parsePreferHeader(preferHeader) || {};
setRoute(app, path) {
if(preferredStatusCode)
logger.debug(`Searching requested response with status code ${preferredStatusCode}`);
else
logger.debug('Searching first response');
return path.getResponse(preferredStatusCode, preferredExampleName);
};
logger.debug(`Processing schema path ${path.httpMethod.toUpperCase()} ${path.uri}`);
const getResponseMemo = memoize(getResponse, {
maxSize: 10
});
const expressHttpMethod = path.httpMethod.toLowerCase();
app[expressHttpMethod](uris, (req, res) => {
const uris = this._normalizeExpressPath(path.uri);
this._checkContentType(req);
app[expressHttpMethod](uris, handleRequest(path));
const {
query,
params,
headers,
cookies,
body: requestBody
} = req;
const failedValidations = path.validateRequestParameters({
query,
path: params,
headers,
cookies,
requestBody
});
if(failedValidations.length)
return this.sendResponse(req, res, { errors: failedValidations }, 400);
const preferHeader = req.header('prefer') || '';
const { statusCode, headers: responseHeaders, body } =
getResponseMemo(req.path, JSON.stringify(req.query), preferHeader, JSON.stringify(requestBody));
return this.sendResponse(req, res, body, statusCode, responseHeaders);
});
return uris.map(uri => {
return logger.info(`Handling route ${path.httpMethod.toUpperCase()} ${uri}`);
});
return uris.map(uri => {
return logger.info(`Handling route ${path.httpMethod.toUpperCase()} ${uri}`);
});
}
app.all('*', this._notFoundHandler.bind(this));
startServer(app) {
return new Promise((resolve, reject) => {

@@ -221,3 +185,3 @@ this.server = app.listen(this.port);

.set(headers)
.set('x-powered-by', 'jormaechea/open-api-mock')
.set('x-powered-by', 'jormaechea/open-api-mocker')
.json(body);

@@ -224,0 +188,0 @@ }

'use strict';
const ParserError = require('../errors/parser-error');
const Path = require('./path');

@@ -8,2 +7,3 @@ const PathsStruct = require('./structs');

const { knownHttpMethods } = require('../utils/http-methods');
const enhanceStructValidationError = require('../utils/enhance-struct-validation-error');

@@ -31,7 +31,3 @@ class Parser {

} catch(e) {
const path = e.path
.reduce((acum, pathPart) => `${acum}.${pathPart}`, 'paths');
throw new ParserError(e.message, path);
throw enhanceStructValidationError(e, 'paths');
}

@@ -38,0 +34,0 @@ }

@@ -59,9 +59,3 @@ 'use strict';

if(!content) {
// Cannot validate the body if it's content is not defined
logger.warn('Missing content for request body');
return [];
}
if(!content['application/json']) {
if(!content || !content['application/json'] || !content['application/json'].schema) {
// Cannot validate the body if it's application/json content is not defined

@@ -72,8 +66,2 @@ logger.warn('Missing application/json content for request body');

if(!content['application/json'].schema) {
// Cannot validate the body if it's application/json content schema is not defined
logger.warn('Missing application/json content schema for request body');
return [];
}
// Validate the body

@@ -80,0 +68,0 @@ const { schema } = content['application/json'];

@@ -10,11 +10,9 @@ 'use strict';

class ResponseGenerator {
static generate(schemaResponse, preferredExampleName) {
if(schemaResponse.example)
return schemaResponse.example;
if(schemaResponse.examples && Object.values(schemaResponse.examples).length) {
if(preferredExampleName && schemaResponse.examples[preferredExampleName] && schemaResponse.examples[preferredExampleName].value)
return schemaResponse.examples[preferredExampleName].value;
if(Object.values(schemaResponse.examples)[0].value)
return Object.values(schemaResponse.examples)[0].value;
if(schemaResponse.example || (schemaResponse.examples && Object.values(schemaResponse.examples).length)) {
const bestExample = this.getBestExample(schemaResponse, preferredExampleName);
if(bestExample !== undefined)
return bestExample;
}

@@ -25,11 +23,18 @@

if(schemaResponse.schema)
return this.generateBySchema(schemaResponse.schema);
if(schemaResponse.schema || schemaResponse.type)
return this.generateBySchema(schemaResponse.schema || schemaResponse);
if(schemaResponse.type)
return this.generateBySchema(schemaResponse);
throw new Error(`Could not generate response: invalid schema: ${JSON.stringify(schemaResponse)}`);
}
static getBestExample(schemaResponse, preferredExampleName) {
if(schemaResponse.example)
return schemaResponse.example;
if(preferredExampleName && schemaResponse.examples[preferredExampleName] && schemaResponse.examples[preferredExampleName].value)
return schemaResponse.examples[preferredExampleName].value;
if(Object.values(schemaResponse.examples)[0].value)
return Object.values(schemaResponse.examples)[0].value;
}
static generateByEnum(enumOptions) {

@@ -40,2 +45,3 @@ return enumOptions[0];

static generateBySchema(schemaResponse) {
if(schemaResponse.example)

@@ -52,8 +58,5 @@ return schemaResponse.example;

if(schemaResponse.oneOf)
return this.generate(schemaResponse.oneOf[0]);
if(schemaResponse.oneOf || schemaResponse.anyOf)
return this.generate((schemaResponse.oneOf || schemaResponse.anyOf)[0]);
if(schemaResponse.anyOf)
return this.generate(schemaResponse.anyOf[0]);
const fakerExtension = schemaResponse['x-faker'];

@@ -70,2 +73,6 @@ if(fakerExtension) {

return this.generateByType(schemaResponse);
}
static generateByType(schemaResponse) {
switch(schemaResponse.type) {

@@ -96,4 +103,5 @@ case 'array':

static generateByFaker(fakerString) {
// Check if faker string is a template string
if(fakerString.includes('{{') && fakerString.includes('}}'))
if(fakerString.match(/\{\{.+\}\}/))
return faker.fake(fakerString);

@@ -104,24 +112,11 @@

);
if(!fakerRegex) {
throw new Error(
'Faker extension method is not in the right format. Expecting <namespace>.<method>(<args>) format.'
);
}
if(!fakerRegex)
throw new Error('Faker extension method is not in the right format. Expecting <namespace>.<method> or <namespace>.<method>(<json-args>) format.');
const { namespace, method, argsString } = fakerRegex.groups;
if(!(namespace in faker)) {
throw new Error(
`Invalid faker namespace used. Must be one of ${Object.keys(faker).join(
','
)}`
);
}
if(!(method in faker[namespace])) {
throw new Error(
`Method '${method}' not found in faker namespace '${namespace}'. Must be one of ${Object.keys(
faker[namespace]
).join(',')}`
);
}
if(!faker[namespace] || !faker[namespace][method])
throw new Error(`Faker method '${namespace}.${method}' not found`);
const args = argsString ? JSON.parse(`[${argsString}]`) : [];

@@ -128,0 +123,0 @@

'use strict';
const ParserError = require('../errors/parser-error');
const SecurityRequirement = require('./security-requirement');
const SecurityRequirementsStruct = require('./structs');
const enhanceStructValidationError = require('../utils/enhance-struct-validation-error');

@@ -27,7 +27,3 @@ class Parser {

} catch(e) {
const path = e.path
.reduce((acum, pathPart) => `${acum}.${pathPart}`, 'security');
throw new ParserError(e.message, path);
throw enhanceStructValidationError(e, 'security');
}

@@ -34,0 +30,0 @@ }

'use strict';
const ParserError = require('../errors/parser-error');
const Server = require('./server');
const ServersStruct = require('./structs');
const extractExtensions = require('../utils/extract-extensions');
const enhanceStructValidationError = require('../utils/enhance-struct-validation-error');

@@ -31,7 +32,3 @@ class Parser {

} catch(e) {
const path = e.path
.reduce((acum, pathPart) => `${acum}.${pathPart}`, 'servers');
throw new ParserError(e.message, path);
throw enhanceStructValidationError(e, 'servers');
}

@@ -42,4 +39,3 @@ }

const extensionProps = Object.entries(otherProps)
.filter(([propName]) => propName.substr(0, 2) === 'x-');
const extensionProps = extractExtensions(otherProps);

@@ -46,0 +42,0 @@ return new Server({

'use strict';
const ParserError = require('../errors/parser-error');
const Tag = require('./tag');
const TagsStruct = require('./structs');
const extractExtensions = require('../utils/extract-extensions');
const enhanceStructValidationError = require('../utils/enhance-struct-validation-error');

@@ -27,7 +28,3 @@ class Parser {

} catch(e) {
const path = e.path
.reduce((acum, pathPart) => `${acum}.${pathPart}`, 'tags');
throw new ParserError(e.message, path);
throw enhanceStructValidationError(e, 'tags');
}

@@ -38,4 +35,3 @@ }

const extensionProps = Object.entries(otherProps)
.filter(([propName]) => propName.substr(0, 2) === 'x-');
const extensionProps = extractExtensions(otherProps);

@@ -42,0 +38,0 @@ return new Tag({

{
"name": "open-api-mocker",
"version": "1.7.0",
"version": "1.7.1",
"description": "A mock server based in Open API Specification",

@@ -5,0 +5,0 @@ "main": "lib/open-api-mocker.js",

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