Skip to content

Commit

Permalink
feat(api): Added optional longError option to isValid()
Browse files Browse the repository at this point in the history
Depending on use, violations reportd by isValid are either serialized or used as an object. This
flag provides caller control on how much information is put into the error message, allowing for
minimal and clean errors when the errors are being processed, and convenience in dumping all
violations to console when that is more appropriate. Turns out, this code was being repeated in each
use of the API. This refactoring just mirrors real use.
  • Loading branch information
sramam committed Nov 20, 2017
1 parent b9e63ba commit df56bd0
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 22 deletions.
5 changes: 3 additions & 2 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export declare class SchemaError extends Error {
_errors: Array<object>;
constructor(message: any, errors: any);
_serialized: string;
constructor(message: any, errors: any, long?: boolean);
readonly errors: object[];
serialize(): string;
}
export declare const isValid: (schema: any, data?: any) => Promise<boolean>;
export declare const isValid: (schema: any, data?: any, longError?: boolean) => Promise<boolean>;
26 changes: 16 additions & 10 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,22 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
var _this = this;
Object.defineProperty(exports, "__esModule", { value: true });
var Ajv = require("ajv");
var merge = require("lodash.merge");
var schemaRef = require('json-schema-ref-parser');
var ajv04 = require('ajv/lib/refs/json-schema-draft-04.json');
var SchemaError = (function (_super) {
__extends(SchemaError, _super);
function SchemaError(message, errors) {
var _this = _super.call(this, message) || this;
function SchemaError(message, errors, long) {
var _this = this;
var _serialized = message + "\n" + JSON.stringify(errors.map(function (v) {
var w = merge({}, v);
delete w['parentSchema'];
return w;
}), null, 2);
var msg = long ? _serialized : message;
_this = _super.call(this, msg) || this;
_this._errors = errors;
_this._serialized = _serialized;
Object.setPrototypeOf(_this, SchemaError.prototype);
return _this;
}
Expand All @@ -65,11 +74,7 @@ var SchemaError = (function (_super) {
configurable: true
});
SchemaError.prototype.serialize = function () {
var violations = this._errors.map(function (v) {
delete v['parentSchema'];
return v;
});
return this.message + "\n" + JSON.stringify(violations, null, 2);
return this._serialized;
};
return SchemaError;
}(Error));
Expand All @@ -79,8 +84,9 @@ function getVersion(schema) {
var m = s.match(/.*draft-0(\d).*/);
return m ? m[1] : null;
}
exports.isValid = function (schema, data) {
exports.isValid = function (schema, data, longError) {
if (data === void 0) { data = null; }
if (longError === void 0) { longError = false; }
return __awaiter(_this, void 0, void 0, function () {
var fullSchema, ajv;
return __generator(this, function (_a) {
Expand All @@ -97,10 +103,10 @@ exports.isValid = function (schema, data) {
ajv.addMetaSchema(ajv04);
}
if (!ajv.validateSchema(fullSchema)) {
throw new SchemaError("Invalid schema", ajv.errors);
throw new SchemaError("Invalid schema", ajv.errors, longError);
}
if (data && !ajv.validate(fullSchema, data)) {
throw new SchemaError("Invalid data", ajv.errors);
throw new SchemaError("Invalid data", ajv.errors, longError);
}
return [2, true];
}
Expand Down
30 changes: 20 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@

import * as Ajv from 'ajv';
import * as a from 'awaiting';
import * as merge from 'lodash.merge';

const schemaRef = require('json-schema-ref-parser');
const ajv04 = require('ajv/lib/refs/json-schema-draft-04.json');

// const deref = require('json-schema-deref');
export class SchemaError extends Error {
_errors: Array<object>;
constructor(message, errors) {
super(message) // tslint:disable-line
_serialized: string;
constructor(message, errors, long?: boolean) {
const _serialized = `${message}\n${JSON.stringify(errors.map(v => {
const w = merge({}, v);
delete w['parentSchema'];
return w;
}), null, 2)}`;
const msg = long ? _serialized : message;
super(msg);
this._errors = errors;
this._serialized = _serialized;
Object.setPrototypeOf(this, SchemaError.prototype);
}
get errors() {
return this._errors;
}

serialize() {
const violations = this._errors.map(v => {
delete v['parentSchema'];
return v;
});
return `${this.message}\n${JSON.stringify(violations, null, 2)}`;
return this._serialized;
}
}

Expand All @@ -43,9 +48,14 @@ function getVersion(schema) {
* @async
* @param schema schema to validate data against
* @param data data to validate
* @param longError serializes all schema violations
* @returns Promise<boolean>
*/
export const isValid = async (schema, data = null): Promise<boolean> => {
export const isValid = async (
schema,
data = null,
longError = false
): Promise<boolean> => {
const fullSchema = await schemaRef.dereference(schema);
const ajv = new Ajv({
allErrors: true,
Expand All @@ -56,10 +66,10 @@ export const isValid = async (schema, data = null): Promise<boolean> => {
ajv.addMetaSchema(ajv04);
}
if (!ajv.validateSchema(fullSchema)) {
throw new SchemaError(`Invalid schema`, ajv.errors);
throw new SchemaError(`Invalid schema`, ajv.errors, longError);
}
if (data && !ajv.validate(fullSchema, data)) {
throw new SchemaError(`Invalid data`, ajv.errors);
throw new SchemaError(`Invalid data`, ajv.errors, longError);
}
return true;
};
Expand Down
24 changes: 24 additions & 0 deletions src/test/specs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { isValid } from '../..';
import { fixtures } from '../fixtures';
import { serializedString } from '../fixtures/serializedString';
import * as execa from 'execa';
import * as fs from 'fs';

const JSON2 = j => JSON.stringify(j, null, 2);

Expand Down Expand Up @@ -81,6 +82,29 @@ test('data-check API schema-fail', async (t) => {
}
});

test('data-check API schema-ok, data-fail longError', async (t) => {
try {
await isValid(fixtures.valid.schema, fixtures.invalid.data, true);
t.fail('invalid *data* passed validation!');
} catch (err) {
t.regex(
err.errors[0].message,
/should NOT have additional properties/
);
t.is(
err.message,
serializedString,
err.message
);
t.is(
err.serialize(),
serializedString,
err.serialize()
);
}
});


test('data-check API schema-ok, data-fail', async (t) => {
try {
await isValid(fixtures.valid.schema, fixtures.invalid.data);
Expand Down

0 comments on commit df56bd0

Please sign in to comment.