jsonschema
Introduction
jsonschema is a lightweight and easy-to-use JSON schema validator that fully supports JSON Schema versions through draft-07.
How to Install
ohpm install @ohos/jsonschema
For details about the OpenHarmony ohpm environment configuration, see OpenHarmony HAR.
How to Use
After jsonschema is installed, import jsonschema on the target page and initialize it.
import { Validator, ValidatorResult, ValidationError, SchemaError, validate } from '@ohos/jsonschema'
let v = new Validator();
Performing Simple Object Validation
let instance = 4;
let schema = { "type": "number" }; // Define the schema.
let result = v.validate(instance, schema).valid; // Start validation and obtain the result.
This function converts the provided path into a regular expression and returns a RegExp object that contains information related to the regular expression for validation or path concatenation and conversion.
Performing Complex Validation with Custom Rules and Schema References
// Address, to be embedded on Person
let addressSchema = {
"id": "/SimpleAddress",
"type": "object",
"properties": {
"lines": {
"type": "array",
"items": {"type": "string"}
},
"zip": {"type": "string"},
"city": {"type": "string"},
"country": {"type": "string"}
},
"required": ["country"]
};
// Person
let schema = {
"id": "/SimplePerson",
"type": "object",
"properties": {
"name": {"type": "string"},
"address": {"$ref": "/SimpleAddress"},
"votes": {"type": "integer", "minimum": 1}
}
};
let p = {
"name": "Barack Obama",
"address": {
"lines": [ "1600 Pennsylvania Avenue Northwest" ],
"zip": "DC 20500",
"city": "Washington",
"country": "USA"
},
"votes": "lots"
};
v.addSchema(addressSchema, '/SimpleAddress');
let result = v.validate(p, schema).valid;
Setting Custom Formats
// Add a custom format.
Validator.prototype.customFormats.myFormat = function (input) {
return input === 'myFormat';
};
let v1 = new Validator();
// Validate format name myFormat. The result is true.
let result1 = v1.validate('myFormat', { type: 'string', format: 'myFormat' }).valid;
// Validate format name foo. The result is false.
let result2 = v1.validate('foo', { type: 'string', format: 'myFormat' }).valid;
The Validator.prototype.customFormats settings only affect the specific validator instance to which they are applied, so you can create multiple validator instances to handle various formats in different schemas throughout your application.
Using Nested Errors
let schema = {
oneOf: [
{ type: 'string', minLength: 32, maxLength: 32 },
{ type: 'string', maxLength: 16 },
{ type: 'number' },
]
};
let result = v.validate('This string is 28 chars long', schema, { nestedErrors: true });
// The value of result.toString() is as follows:
// 0: instance does not meet minimum length of 32
// 1: instance does not meet maximum length of 16
// 2: instance is not of a type(s) number
// 3: instance is not exactly one from [subschema 0],[subschema 1],[subschema 2]
When multiple validation items are set and nestedErrors is set to true, the result contains detailed error information for each validation item that fails. The validation process does not terminate after the first failed check, allowing it to capture and report on all validation errors.
Setting Custom Keywords
v.attributes.contains = function validateContains(instance, schema, options, ctx) {
if(typeof instance !== 'string') return;
// @ts-ignore Check the type of the custom keyword.
if(typeof schema.contains !== 'string'){
throw new SchemaError('"contains" expects a string', schema);
}
// @ts-ignore Check whether the instance contains the custom keyword.
if(instance.indexOf(schema.contains)<0){
// @ts-ignore
return 'does not contain the string ' + JSON.stringify(schema.contains);
}
// @ts-ignore Check the length of the custom keyword.
if (schema.contains.length < 2) {
return '"contains" length must more than 2 ' ;
}
}
// @ts-ignore
let result = v.validate("I am an instance", { type:"string", contains: "I am" }).valid;
You can set a custom keyword (for example, I am) using contains in the configuration and define validation rules (or example, function validateContains()) for that keyword.
Removing Validation Rules
Initialize data.
schemaArr: object[] = [
{
"type": "number"
},
{
"id": "/simplePerson",
"type": "object",
"properties": {
"name": { "type": "string" },
"address": { "$ref": "/SimpleAddress" },
"votes": { "type": "integer", "minimum": 1 }
}
},
{
"type": "array",
"items": {
"properties": {
"name": { "type": "string" },
"lastname": { "type": "string" }
},
"required": ["name", "lastname"]
}
},
]
@State cacheSchemaNum: number = 0;
@State isFinish: boolean = false;
Start to add or remove rules.
let initSchema = {
"id": "/SimplePerson",
"type": "object",
"properties": {
"name": { "type": "string" },
"address": { "$ref": "/SimpleAddress" },
"votes": { "type": "integer", "minimum": 1 }
}
}
v.addSchema(initSchema); // Add an initialization schema.
this.importNextSchema(v); // Initiate the recursive method to start removing or adding validation rules.
let result = this.cacheSchemaNum > = 0; // Detect whether the removal and addition process is executed by monitoring the change in cacheSchemaNum.
importNextSchema(v: Validator) {
let nextSchema = v.unresolvedRefs.shift(); // Remove the validation rule.
if (this.cacheSchemaNum >= this.schemaArr.length) {
this.isFinish = true;
return
}
if (!nextSchema) {
this.isFinish = true;
return;
}
console.log ('nextSchema: ${JSON.stringify(nextSchema) }') // Print the removed validation rule.
v.addSchema(this.schemaArr[this.cacheSchemaNum]); // Continue to add the next validation rule.
this.cacheSchemaNum++;
this.importNextSchema(v); // Recursively call this method to keep removing and adding validation rules.
}
By using Validator.unresolvedRefs.shift(), you can remove certain rules set for the validator, and then add different rules. In this way, you can create a diverse set of validation rules with a single validator for complex validation scenarios.
Preprocessing Attributes
Preprocess the attribute values to be validated before the actual validation, including null checks and type conversions.
preValidate(object, key, schema, options, ctx) {
let value = object[key];
if (typeof value === 'undefined') return;
// Test if the schema declares a type, but the type keyword fails validation
if (schema.type
&& v1.attributes.type.call(v1, value, schema, options, ctx.makeChild(schema, key))) {
// If the type is "number" but the instance is not a number, cast it
if (schema.type === 'number' && typeof value !== 'number') {
object[key] = parseFloat(value);
return;
}
// If the type is "string" but the instance is not a string, cast it
if (schema.type === 'string' && typeof value !== 'string') {
object[key] = String(value).toString();
return;
}
}
};
Set validation rules and start the validation process.
const schema = {
'properties': {
'name': { 'type': 'string' },
'quantity': { 'type': 'number' }
}
};
const instance = {
name: 123,
quantity: '2'
}
let v0 = new Validator();
let v1 = new Validator();
// No attribute preprocessing
let result0 = v0.validate(instance, schema).valid;
// Attribute preprocessing
let result1 = v1.validate(instance, schema, { preValidateProperty: this.preValidate }).valid;
Preprocessing certain attributes can simplify the validation rules and improve the validation success rate.
Skipping Keyword Validation
let schema = {
"id": "/SimplePerson",
"type": "object",
"properties": {
"name": { "type": "string" },
"sex": { "type": "number", "minimum": 50 },
"votes": { "type": "integer", "minimum": 1 }
}
};
let p = {
"name": "Zhang San",
"sex": 45,
"votes": 22
};
let v0 = new Validator();
let result0 = v0.validate(p, schema, { skipAttributes: ["minimum"] }).valid;
Using the skipAttributes option to skip the validation for certain keywords can prevent validation failures caused by unnecessary rules in imported template validation schemas. For example, if the template specifies a minimum age of 50, but your project does not impose such a limit, you can skip the minimum value validation for the age attribute.
Allowing Failures for Unknown Keywords
let v0 = new Validator();
let schema = {
type: "string",
format: "email",
example: "foo",
};
let result0 = v0.validate("Name", schema, { allowUnknownAttributes: true }).valid;
let v1 = new Validator();
let result1 = v1.validate("Name", schema, { allowUnknownAttributes: false });
// result0 false
// result1 throw err
By default, jsonschema ignores unknown schema keywords, and validation failures return a false result without throwing an error. To handle validation failures as exceptions, set allowUnknownAttributes to false to interrupt the validation process and respond to the error messages accordingly.
Available APIs
| API | Parameter | Return Value | Description |
|---|---|---|---|
| new Validator() | N/A | Validator | Creates a validator object. |
| Validator.validate() | instance: any, schema: Schema, options?: Options, ctx?: SchemaContext |
ValidatorResult | Validates a schema. |
| Validator.addSchema() | schema?: Schema, uri?: string |
Schema|void | Adds a schema to the validator. |
| validate() | instance: any, schema: any, options?: Options |
ValidatorResult | Validates a schema. |
| rewrite() | instance: any, schema: Schema, options: Options, ctx: SchemaContext |
any | Alters the instance value after successful validation. |
| preValidateProperty() | instance: any, key: string, schema: Schema, options: Options, ctx: SchemaContext |
any | Processes this property before validation. |
| customFormats() | input: any | boolean | Adds custom formats. |
| attributes() | instance: any, schema: Schema, options: Options, ctx: SchemaContext | string|ValidatorResult | Specifies validation keywords. |
| ValidatorResult.addError() | detail: string|ErrorDetail | ValidationError | Adds error information to this ValidatorResult object. |
| ValidatorResult.toString() | N/A | string | Converts this ValidatorResult object to a string. |
| ValidationError.toString() | N/A | string | Converts this ValidationError object to a string. |
| shift() | N/A | T | undefined | Removes and returns the added validation rule. |
For more information, see jsonschema and Unit Test Cases.
Constraints
This project has been verified in the following versions:
- DevEco Studio: NEXT Beta1-5.0.3.806, SDK: API 12 Release (5.0.0.66)
- DevEco Studio: 4.0 (4.0.3.513), SDK: API 10 (4.0.10.10)
Directory Structure
|---- json-schema
| |---- entry # Sample code
| |---- pages # Application pages, divided based on the features of json-schema
| |---- AllFuntionString.ts # Strings for display on the UI
| |---- JumpPathConfig.ts # Page redirection configuration, which is used to display list data on the homepage and obtain redirection parameters
|
| |---- README.md # Readme
How to Contribute
If you find any problem when using the project, submit an issue or a PR.
License
This project is licensed under MIT License.