Socket
Socket
Sign inDemoInstall

koas-core

Package Overview
Dependencies
62
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.4.1 to 0.5.0

lib/jsonRefs.d.ts

80

lib/index.d.ts

@@ -1,11 +0,57 @@

import { Middleware } from 'koa';
import { PreValidatePropertyFunction, RewriteFunction, ValidatorResult } from 'jsonschema';
import { Context, Middleware } from 'koa';
import { OpenAPIV3 } from 'openapi-types';
import { SchemaValidationError, Validator } from './validation';
export { SchemaValidationError, Validator };
export interface AdvancedOptions {
import { JSONRefResolver } from './jsonRefs';
import { SchemaValidationError } from './validation';
export { JSONRefResolver, SchemaValidationError };
export interface KoasOptions {
/**
* A function for creating a custom JSON schema validator.
* Convert a schema validation error to an HTTP response body.
*
* @param error - The error that as thrown.
* @param ctx - The Koa context.
* @returns The HTTP response body.
*/
createValidator?: (spec?: OpenAPIV3.Document) => Validator;
onSchemaValidationError?: (error: SchemaValidationError, ctx: Context) => unknown;
}
interface ValidateOptions {
/**
* The error message.
*
* @default 'JSON schema validation failed'
*/
message?: string;
/**
* A function to rewrite a property before it’s passed to the JSON schema validation
*/
preValidateProperty?: PreValidatePropertyFunction;
/**
* A function to rewrite a property after has passed JSON schema validation
*/
rewrite?: RewriteFunction;
/**
* The HTTP status code to set.
*
* @default 400
*/
status?: number;
/**
* Whether or not to throw an error if the schema validation failed.
*
* If `false`, the `ValidatorResult` instance will be returned instead.
*
* @default true
*/
throw?: boolean;
}
/**
* A JSON schema validator function.
*
* @param instance - The instance to validate
* @param schema - The JSON schema to use.
* @param options - Additional jsonschema validation options.
*
* @returns The validator result
*/
export declare type Validator = (instance: unknown, schema: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject, options?: ValidateOptions) => ValidatorResult;
declare module 'koa' {

@@ -21,15 +67,15 @@ interface DefaultContext {

/**
*
* The full OpenAPI document
*/
operationObject?: OpenAPIV3.OperationObject;
document: OpenAPIV3.Document;
/**
*
* The OpenAPI operation object that describes the current request context.
*/
openApiObject: OpenAPIV3.Document;
operationObject?: OpenAPIV3.OperationObject;
/**
*
* The path item object that describes the current request context.
*/
pathItemObject?: OpenAPIV3.PathItemObject;
/**
*
* A function to apply JSON schema validation in the context of the OpenAPI document.
*/

@@ -46,11 +92,11 @@ validate: Validator;

*/
rawSpec: OpenAPIV3.Document;
document: OpenAPIV3.Document;
/**
*
*/
runAlways: (middleware: Middleware) => Middleware;
resolveRef: JSONRefResolver;
/**
*
*/
spec: OpenAPIV3.Document;
runAlways: (middleware: Middleware) => Middleware;
/**

@@ -64,3 +110,3 @@ *

*
* @param spec - The OpenAPI document from which to create an API.
* @param document - The OpenAPI document from which to create an API.
* @param middlewares - The Koas middlewares to use for creating an API.

@@ -71,2 +117,2 @@ * @param options - Advanced options

*/
export declare function koas(spec: OpenAPIV3.Document, middlewares?: Plugin[], { createValidator }?: AdvancedOptions): Promise<Middleware>;
export declare function koas(document: OpenAPIV3.Document, middlewares?: Plugin[], { onSchemaValidationError, }?: KoasOptions): Middleware;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.koas = exports.SchemaValidationError = void 0;
const RefParser = require("@apidevtools/json-schema-ref-parser");
const compose = require("koa-compose");
const lodash_1 = require("lodash");
const jsonRefs_1 = require("./jsonRefs");
const matcher_1 = require("./matcher");

@@ -39,3 +38,3 @@ const validation_1 = require("./validation");

*
* @param spec - The OpenAPI document from which to create an API.
* @param document - The OpenAPI document from which to create an API.
* @param middlewares - The Koas middlewares to use for creating an API.

@@ -46,19 +45,31 @@ * @param options - Advanced options

*/
async function koas(spec, middlewares = [], { createValidator = validation_1.createDefaultValidator } = {}) {
const dereferencedSpec = (await RefParser.dereference(lodash_1.cloneDeep(spec)));
const matchers = Object.entries(dereferencedSpec.paths).map(([pathTemplate, pathItemObject]) => {
const matcher = matcher_1.createMatcher(pathTemplate, pathItemObject.parameters);
function koas(document, middlewares = [], { onSchemaValidationError = (error) => ({ message: error.message, errors: error.result.errors }), } = {}) {
const resolveRef = jsonRefs_1.createResolver(document);
const matchers = Object.entries(document.paths).map(([pathTemplate, pathItemObject]) => {
const matcher = matcher_1.createMatcher(pathTemplate, resolveRef, pathItemObject.parameters);
return [matcher, pathItemObject];
});
const validate = createValidator(spec);
const injected = middlewares.map((middleware) => middleware({
rawSpec: spec,
const validator = validation_1.createValidator(document);
const validate = (instance, schema, { message = 'JSON schema validation failed', preValidateProperty, rewrite, status, throw: throwError = true, } = {}) => {
const result = validator.validate(instance, schema, {
base: '#',
rewrite,
preValidateProperty,
});
if (throwError && !result.valid) {
throw new validation_1.SchemaValidationError(message, { result, status });
}
return result;
};
const pluginOptions = {
document,
resolveRef,
runAlways: markRunAlways,
spec: dereferencedSpec,
validate,
}));
};
const injected = middlewares.map((middleware) => middleware(pluginOptions));
const composed = compose(injected);
// @ts-expect-error This is an internal hack.
const runAlways = compose(injected.filter((middleware) => middleware[RUN_ALWAYS]));
return (ctx, next) => {
return async (ctx, next) => {
let params;

@@ -69,21 +80,31 @@ const match = matchers.find(([matcher]) => {

});
ctx.openApi = { openApiObject: spec, validate };
if (!match) {
return runAlways(ctx, next);
ctx.openApi = { document, validate };
try {
if (!match) {
return await runAlways(ctx, next);
}
const [, pathItemObject] = match;
ctx.openApi.pathItemObject = pathItemObject;
ctx.params = params;
const method = ctx.method.toLowerCase();
if (!methods.has(method)) {
return await runAlways(ctx, next);
}
const operationObject = pathItemObject[method];
if (!operationObject) {
return await runAlways(ctx, next);
}
ctx.openApi.operationObject = operationObject;
await composed(ctx, next);
}
const [, pathItemObject] = match;
ctx.openApi.pathItemObject = pathItemObject;
ctx.params = params;
const method = ctx.method.toLowerCase();
if (!methods.has(method)) {
return runAlways(ctx, next);
catch (error) {
if (error instanceof validation_1.SchemaValidationError) {
ctx.status = error.status;
ctx.body = onSchemaValidationError(error, ctx);
return;
}
throw error;
}
const operationObject = pathItemObject[method];
if (!operationObject) {
return runAlways(ctx, next);
}
ctx.openApi.operationObject = operationObject;
return composed(ctx, next);
};
}
exports.koas = koas;
import { OpenAPIV3 } from 'openapi-types';
import { JSONRefResolver } from './jsonRefs';
/**

@@ -14,2 +15,3 @@ * A matcher function for extracting URL parameters.

* @param pathTemplate - The OpenAPI path template for which to create a matcher.
* @param resolveRef - A JSON reference resolver.
* @param pathParameters - The OpenAPI path parameter objects used to determine how to process the

@@ -20,2 +22,2 @@ * extracted parameters.

*/
export declare function createMatcher(pathTemplate: string, pathParameters?: OpenAPIV3.ParameterObject[]): MatcherFunction;
export declare function createMatcher(pathTemplate: string, resolveRef: JSONRefResolver, pathParameters?: (OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject)[]): MatcherFunction;

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

* @param pathTemplate - The OpenAPI path template for which to create a matcher.
* @param resolveRef - A JSON reference resolver.
* @param pathParameters - The OpenAPI path parameter objects used to determine how to process the

@@ -14,5 +15,6 @@ * extracted parameters.

*/
function createMatcher(pathTemplate, pathParameters = []) {
function createMatcher(pathTemplate, resolveRef, pathParameters = []) {
const arrayNames = new Set(pathParameters
.filter(({ schema = {} }) => schema.type === 'array')
.map(resolveRef)
.filter(({ schema = {} }) => resolveRef(schema).type === 'array')
.map(({ name }) => name));

@@ -19,0 +21,0 @@ const names = [];

@@ -0,15 +1,30 @@

import { Validator, ValidatorResult } from 'jsonschema';
import { OpenAPIV3 } from 'openapi-types';
interface SchemaValidationErrorOptions {
/**
* The HTTP status code for the validation error.
*/
status?: number;
/**
* The JSON schema validator result.
*/
result: ValidatorResult;
}
/**
* A JSSO validator agnostic schema validation error.
* An error that’s thrown if JSON schema validation fails.
*/
export declare class SchemaValidationError extends Error {
errors: unknown[];
constructor(message: string, errors: unknown[]);
status: number;
result: ValidatorResult;
/**
* @param message - The error message to throw.
* @param options - The error options.
*/
constructor(message: string, { result, status }: SchemaValidationErrorOptions);
}
export declare type Validator = (data: unknown, schema: OpenAPIV3.SchemaObject) => Promise<boolean>;
/**
* Create a ZSchema based JSON schema validator.
*
* @returns A JSON schema validator.
* @param document - THe OpenAPI document to create a JSON schema validator for.
* @returns A configured JSON schema validator.
*/
export declare function createDefaultValidator(): Validator;
export declare function createValidator({ components }: OpenAPIV3.Document): Validator;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDefaultValidator = exports.SchemaValidationError = void 0;
const ZSchema = require("z-schema");
ZSchema.registerFormat('binary', () => true);
exports.createValidator = exports.SchemaValidationError = void 0;
const jsonschema_1 = require("jsonschema");
const jsonRefs_1 = require("./jsonRefs");
/**
* A JSSO validator agnostic schema validation error.
* Iterate over object entries.
*
* @param object - The object to iterate over. This may be null.
* @param iterator - A function which will be called with the key and value.
*/
function iter(object, iterator) {
if (object) {
Object.entries(object).forEach(([key, value]) => iterator(key, value));
}
}
/**
* An error that’s thrown if JSON schema validation fails.
*/
class SchemaValidationError extends Error {
constructor(message, errors) {
/**
* @param message - The error message to throw.
* @param options - The error options.
*/
constructor(message, { result, status = 400 }) {
super(message);
this.name = 'SchemaValidationError';
this.errors = errors;
Error.captureStackTrace(this, this.constructor);
this.status = status;
this.result = result;
}

@@ -19,23 +34,48 @@ }

/**
* Create a ZSchema based JSON schema validator.
*
* @returns A JSON schema validator.
* @param document - THe OpenAPI document to create a JSON schema validator for.
* @returns A configured JSON schema validator.
*/
function createDefaultValidator() {
const validator = new ZSchema({
assumeAdditional: true,
breakOnFirstError: false,
reportPathAsArray: true,
});
return (data, schema) => new Promise((resolve, reject) => {
validator.validate(data, schema, (errors, valid) => {
if (valid) {
resolve(true);
function createValidator({ components = {} }) {
const validator = new jsonschema_1.Validator();
// Register OpenAPI formats
validator.customFormats.int32 = () => true;
validator.customFormats.int64 = () => true;
validator.customFormats.float = () => true;
validator.customFormats.double = () => true;
validator.customFormats.byte = () => true;
validator.customFormats.binary = () => true;
validator.customFormats.password = () => true;
/**
* Add schemas from a record of JSON schema property wrappers.
*
* @param wrappers - The rescord that holds the JSON schema wrappers
* @param prefix - The prefix of the wrapper.
*/
function procesSchemaWrapper(wrappers, prefix) {
iter(wrappers, (key, wrapper) => {
if ('schema' in wrapper) {
validator.addSchema(wrapper.schema, `${prefix}/${jsonRefs_1.escapeJsonPointer(key)}/schema`);
}
else {
reject(new SchemaValidationError('JSON schema validation failed', errors));
}
});
}
iter(components.schemas, (key, schema) => {
validator.addSchema(schema, `#/components/schemas/${jsonRefs_1.escapeJsonPointer(key)}`);
});
procesSchemaWrapper(components.headers, '#/components/headers');
procesSchemaWrapper(components.parameters, '#/components/parameters');
iter(components.requestBodies, (key, requestBody) => {
if ('content' in requestBody) {
procesSchemaWrapper(requestBody.content, `#/components/requestBodies/${jsonRefs_1.escapeJsonPointer(key)}/content`);
}
});
iter(components.responses, (key, response) => {
if ('headers' in response) {
procesSchemaWrapper(response.headers, `#/components/responses/${jsonRefs_1.escapeJsonPointer(key)}/headers`);
}
if ('content' in response) {
procesSchemaWrapper(response.content, `#/components/responses/${jsonRefs_1.escapeJsonPointer(key)}/content`);
}
});
return validator;
}
exports.createDefaultValidator = createDefaultValidator;
exports.createValidator = createValidator;
{
"name": "koas-core",
"version": "0.4.1",
"version": "0.5.0",
"keywords": [

@@ -29,12 +29,9 @@ "koa",

"dependencies": {
"@apidevtools/json-schema-ref-parser": "^9.0.6",
"@types/koa": "^2.11.4",
"@types/lodash": "^4.14.161",
"@types/koa": "^2.11.7",
"jsonschema": "^1.4.0",
"koa-compose": "^4.1.0",
"lodash": "^4.17.20",
"openapi-types": "^7.0.1",
"z-schema": "^4.2.3"
"openapi-types": "^7.2.3"
},
"devDependencies": {
"axios-test-instance": "^3.1.1"
"axios-test-instance": "^4.0.0"
},

@@ -41,0 +38,0 @@ "peerDependencies": {

# Koas-core
> [Koa][] + [Open API Specification][] = Koas
> [Koa][] + [OpenAPI Specification][] = Koas

@@ -22,3 +22,3 @@ Koas aims to make it easy to write a RESTful API based on Koa and an Open API V3 Specification.

const spec = {
const document = {
openapi: '3.0.2',

@@ -38,16 +38,9 @@ info: {

async function main() {
const app = new Koa();
app.use(
await koas(spec, [
// Koas plugins go here.
]),
);
app.listen(3333);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
const app = new Koa();
app.use(
koas(document, [
// Koas plugins go here.
]),
);
app.listen(3333);
```

@@ -64,3 +57,3 @@

function myPlugin(options) {
return (koasPluginOptions) => async (ctx, next) => {
return (document, resolveRef, runAlways, validate) => async (ctx, next) => {
await next();

@@ -86,3 +79,3 @@ };

export function myPlugin(options: MyPluginOptions): Plugin {
return (koasPluginOptions) => async (ctx, next) => {
return (document, resolveRef, runAlways, validate) => async (ctx, next) => {
await next();

@@ -92,1 +85,4 @@ };

```
[koa]: https://koajs.com
[openapi specification]: https://spec.openapis.org/oas/v3.0.3
SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc