Skip to main content

How to Validate JSON Input with NodeJS (Schema)

In this article I am going to show you how to validate JSON input using NodeJS.

To validate JSON input using NodeJS you can use a package or library to compare it against a schema.

Step 1. Create a new NodeJS project

mkdir -p ~/projects
cd ~/projects
mkdir json-schema-101
cd json-schema-101

Step 2. Create new files and folders

To create the files and folder for this project:

touch parser.js index.js
mkdir test-files
touch test-files/schema.json test-files/good.json test-files/bad.json

Step 3. Initialize npm

To install packages, scripts, etc. you are going to need to first initialize your project to work with npm.

  • Run this command:
npm init -y

Step 4. Modify package.json

The last command created a new file in the project called package.json.

  • Insert this line into package.json under the description property and save the file:
"type": "module",

Step 5. Install the ajv package

To validate JSON files against a schema, you can use the popular ajv package, by running this command:

npm install --save ajv

Step 6. Define the parser function

Open the project in a code editor, like Visual Studio Code.

In the code editor, edit the parser.js module and paste in the following, then save the file:

// Author: Mitch Allen
// File: parser.js

import { readFileSync } from 'fs';
import Ajv from 'ajv';

const ajv = new Ajv();

export function parser( inputFile, schemaFile ) {

function readJsonFile(file) {
let raw = readFileSync(file);
return JSON.parse(raw);
}

let input = readJsonFile(inputFile);
let schema = readJsonFile(schemaFile);

const isValid = ajv.validate(schema, input);

if (!isValid) {
console.error(JSON.stringify(ajv.errors, null, 2));
return undefined;
}

console.info('[INFO] Valid!');

return input;
}

The code does the following:

  • imports that readFileSync function from the NodeJS fs library
  • imports from the Ajv package
  • creates a new object instance (ajv) of the Ajv package
  • defines a function called parser that takes two arguments: an input file path and a schema file path
  • defines a function for reading JSON files from disk and then parses the raw file data into an object for use in JavaScript
  • calls the function twice to convert both the input file and the schema file to objects
  • passes the two objects to the avj.validate method
  • if the method returns false, then isValid will be false, an error will be echoed to the console and the function will return undefined
  • otherwise the input will be considered valid and returned by the function as an object

Step 7. Define the main function

In the code editor, edit the index.js module and paste in the following, then save the file:

// Author: Mitch Allen
// File: index.js

import { parser } from './parser.js';

function main() {

let args = process.argv.slice(2);

if (args.length < 2) {
console.log('USAGE: node index.js test-files/good.json test-files/schema.json');
return;
}

let [inputFile, schemaFile] = args;

console.log(`input file: ${inputFile}`);
console.log(`schema file: ${schemaFile}`);

let json = parser( inputFile, schemaFile );

if( !json ) {
console.error(`[ERROR] input not valid!`);
return;
}

console.log(JSON.stringify(json,null,2))

}

main();

The code does the following:

  • imports the parser from the module defined in the previous step
  • defines a function called main
  • gets the command line arguments passed to the program (process.argv)
  • because the first two arguments are the program (nodejs) and the file being run (index.js) those arguments are removed using the slice method
  • the argv list variable is assigned the remaining arguments, which should be the input file path and the schema file path
  • if argv does not contain at least two items, a usage statement is echoed to the console and the function returns
  • otherwise the inputFile and schemaFile values are set from argv and their paths are echoed to the console
  • the parser method is called, passing in the inputFile and the schemaFile values
  • the return value is assigned to a variable called json
  • if json is undefined then the parser must have failed, an error is logged to the console and the function should return
  • otherwise the returned object is considered valid and echoed to the console
  • finally the main function is called to validate the input file against the schema

Step 8. Define a simple schema

In the code editor, open test-files/schema.json and paste in the following, then save the file:

{
"type": "object",
"properties": {
"foo": {
"type": "integer"
},
"bar": {
"type": "string"
}
},
"required": [
"foo"
],
"additionalProperties": false
}

The code does the following:

  • defines a JSON object to represent the schema by enclosing the whole thing in brackets
  • sets a root type for the schema which will be an object
  • defines a property called foo that must be an integer
  • defines a property called bar that must be a string
  • declares that the foo property is required or validation will fail
  • declares that no additional properties may be added or validation will fail

Step 9. Define a valid input file

In the code editor, open test-files/good.json and paste in the following, then save the file:

{ 
"foo": 1,
"bar": "abc"
}

Based on the schema, this file should pass validation.

Step 10. Test the input file against the schema

In a terminal window, do the following:

cd ~/projects/json-schema-101
node index.js test-files/good.json test-files/schema.json

The file should pass validation and the JSON input should be echoed to the screen.

Step 11. Test a file that will fail validation

In the code editor, open test-files/bad.json and paste in the following, then save the file:

{ 
"foox": 1,
"bar": "abc"
}

In a terminal window, do the following:

cd ~/projects/json-schema-101
node index.js test-files/bad.json test-files/schema.json

The file should fail validation and an error should be echoed to the screen.

Step 12. Test other scenarios

As an exercise for the reader, based on the schema, modify bad.json to test these other schema rules:

  • What if foo is not an integer?
  • What if bar is not a string?
  • What if foo is missing?
  • What if you add another property?

All of the above should return an error that makes sense based on the invalid input.

Note that if you get errors like an unexpected token that means the input file or your schema does not have a valid JSON structure. That is different from failing validation against a particular schema.

Alternative Parser

I decided to keep the code simple so that it’s readable. But if you would like to see a less readable, but more efficient alternative to the parser, here is the code :

// Author: Mitch Allen
// File: parser.js

import { readFileSync } from 'fs';
import Ajv from 'ajv';

const ajv = new Ajv();

export function parser(inputFile, schemaFile) {

let [input, schema] = [
inputFile,
schemaFile
].map(file => JSON.parse(readFileSync(file)));

const isValid = ajv.validate(schema, input);

if (!isValid) {
console.error(JSON.stringify(ajv.errors, null, 2));
return undefined;
}

console.info('[INFO] Valid!');

return input;
}

Source Code

Conclusion

In this article you learned how to validate a JSON file against a schema. Now you can start writing programs that parse JSON requests, input and configuration files and alert the user if the format is incorrect. For information on how to validate JSON files against more complex schemas I’ve included references below.

References