Skip to content

Commit

Permalink
feat(errors): create proper error classes
Browse files Browse the repository at this point in the history
  • Loading branch information
BelfordZ committed Apr 12, 2019
1 parent 3ed93c9 commit e3393b7
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 19 deletions.
60 changes: 60 additions & 0 deletions src/generate-method-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,37 @@ const makeNotFoundError = (method: types.MethodObject, contentDescriptor: types.
return new Error(errorMessage);
};

/**
* Create a unique identifier for a parameter within a given method.
* This is typically used to create hashmap keys for method to parameter mappings.
*
* @param method The OpenRPC Method which encloses the content descriptor
* @param contentDescriptor The OpenRPC Content Descriptor that is a param in the method
*
* @returns an ID for the param/method combo.
* It follows the format `{method.name}/{indexWithinParams}|{contentDescriptor.name}` where:
* 1. if the method's parameter structure is "by-name", the format returned uses the contentDescriptor.name
* 1. otherwise, the return value will use the params index in the list of params.
*
* @example
* ```typescript
*
* const { generateMethodParamId }
* const methodObject = {
* name: "foo",
* params: [{
* name: "fooParam",
* schema: { type: "integer" }
* }],
* result: {}
* };
* const paramId = generateMethodParamId(methodObject, methodObject.params[0]);
* console.log(paramId);
* // outputs:
* // "foo/0/fooParam"
* ```
*
*/
export function generateMethodParamId(
method: types.MethodObject,
contentDescriptor: types.ContentDescriptorObject,
Expand All @@ -25,6 +56,35 @@ export function generateMethodParamId(
return `${method.name}/${paramId}`;
}

/**
* Create a unique identifier for a result within a given method.
* This is typically used to create hashmap keys for method to result mappings.
*
* @param method The OpenRPC Method which encloses the content descriptor
* @param contentDescriptor The OpenRPC Content Descriptor (either a method param or the result).
*
* @returns an ID for the result/method combo.
* It follows the format `{method.name}/result`.
*
* @example
* ```typescript
*
* const { generateMethodResultId }
* const methodObject = {
* name: "foo",
* params: [],
* result: {
* name: "fooResult",
* schema: { type: "string" }
* }
* };
* const resultId = generateMethodResultId(methodObject, methodObject.result);
* console.log(paramId);
* // outputs:
* // "foo/result"
* ```
*
*/
export function generateMethodResultId(
method: types.MethodObject,
contentDescriptor: types.ContentDescriptorObject,
Expand Down
6 changes: 0 additions & 6 deletions src/get-open-rpc-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import { types } from "@open-rpc/meta-schema";

type TGetOpenRPCDocument = (schema: string) => Promise<types.OpenRPC>;

/**
*
*/
const fetchUrlSchemaFile: TGetOpenRPCDocument = async (schema) => {
try {
const response = await fetch(schema);
Expand All @@ -16,9 +13,6 @@ const fetchUrlSchemaFile: TGetOpenRPCDocument = async (schema) => {
}
};

/**
*
*/
const readSchemaFromFile = async (schema: string) => {
try {
return await readJson(schema);
Expand Down
44 changes: 34 additions & 10 deletions src/parse-open-rpc-document.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
import { pathExists } from "fs-extra";
import refParser from "json-schema-ref-parser";
import validateOpenRPCDocument from "./validate-open-rpc-document";
import validateOpenRPCDocument, { OpenRPCDocumentValidationError } from "./validate-open-rpc-document";
import { types } from "@open-rpc/meta-schema";
import isUrl = require("is-url");
import { fetchUrlSchemaFile, readSchemaFromFile } from "./get-open-rpc-document";

/**
* @ignore
*/
const cwd = process.cwd();

/**
* @ignore
*/
const isJson = (jsonString: string) => {
try { JSON.parse(jsonString); return true; } catch (e) { return false; }
};

/**
* Provides an error interface for OpenRPC Document dereferencing problems
*/
export class OpenRPCDocumentDereferencingError extends Error {

/**
* @param e The error that originated from jsonSchemaRefParser
*/
constructor(e: Error) {
super(`The json schema provided cannot be dereferenced. Received Error: \n ${e.message}`);
}
}

/**
* Resolves an OpenRPC document from a variety of input types. The resolved OpenRPC document
* will be dereferenced and validated against the [meta-schema](https://github.com/open-rpc/meta-schema).
Expand All @@ -23,6 +42,11 @@ const isJson = (jsonString: string) => {
* 2. schema is a url that resolves to an OpenRPC document.
* 3. schema is a file path, where the file at the path contains an OpenRPC document.
*
* @returns The same OpenRPC Document that was passed in, but with all $ref's dereferenced.
*
* @throws [[OpenRPCDocumentValidationError]]
* @throws [[OpenRPCDocumentDereferencingError]]
*
* @example
* ```typescript
*
Expand Down Expand Up @@ -56,15 +80,15 @@ export default async function parseOpenRPCDocument(
parsedSchema = await readSchemaFromFile(schema as string);
}

const errors = validateOpenRPCDocument(parsedSchema);
if (errors) {
throw new Error(`Error Validating schema against meta-schema. \n ${JSON.stringify(errors, undefined, " ")}`);
}
const isValid = validateOpenRPCDocument(parsedSchema);

try {
const openrpcDocument = await refParser.dereference(parsedSchema) as types.OpenRPC;
return openrpcDocument;
} catch (e) {
throw new Error(`The json schema provided cannot be dereferenced. Received Error: \n ${e.message}`);
if (isValid === true) {
try {
return await refParser.dereference(parsedSchema) as types.OpenRPC;
} catch (e) {
throw new OpenRPCDocumentDereferencingError(e);
}
} else {
throw isValid as OpenRPCDocumentValidationError;
}
}
34 changes: 31 additions & 3 deletions src/validate-open-rpc-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,35 @@ import metaSchema, { types } from "@open-rpc/meta-schema";
import JsonSchemaDraft07 from "../lib/json-schema-draft-07.json";
import Ajv from "ajv";

/**
* @ignore
*/
const ajv = new Ajv();
ajv.addMetaSchema(JsonSchemaDraft07, "https://json-schema.org/draft-07/schema#");

/**
* Provides an error interface for OpenRPC Document validation
*/
export class OpenRPCDocumentValidationError extends Error {

/**
* @param errors The errors received by ajv.errors.
*/
constructor(private errors: Ajv.ErrorObject[]) {
super([
"Error validating OpenRPC Document against @open-rpc/meta-schema.",
"The errors found are as follows:",
JSON.stringify(errors, undefined, " "),
].join("\n"));
}
}

/**
* Returns any JSON Schema validation errors that are found with the OpenRPC document passed in.
*
* @param document OpenRPC Document to validate
* @param document OpenRPC Document to validate.
*
* @returns Either true if everything checks out, or a well formatted error.
*
* @example
* ```typescript
Expand All @@ -23,8 +45,14 @@ ajv.addMetaSchema(JsonSchemaDraft07, "https://json-schema.org/draft-07/schema#")
* ```
*
*/
export default function validateOpenRPCDocument(document: types.OpenRPC): Ajv.ErrorObject[] | null | undefined {
export default function validateOpenRPCDocument(
document: types.OpenRPC,
): OpenRPCDocumentValidationError | true {
const result = ajv.validate(metaSchema, document);

return ajv.errors;
if (ajv.errors) {
return new OpenRPCDocumentValidationError(ajv.errors);
} else {
return true;
}
}

0 comments on commit e3393b7

Please # to comment.