Skip to main content

How to Validate YAML Input with NodeJS (Schema)

In this article, I will show you how to validate YAML input using NodeJS.

To validate YAML 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/javascript/yaml-schema-101
cd ~/projects/javascript/yaml-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
touch test-files/good.yaml test-files/bad.yaml
touch test-files/pretty.yaml

Step 3. Initialize npm

To install packages, scripts, etc. you will need first to 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 and js-yaml packages

To validate YAML files against a schema, you can use the popular ajv package.

You'll also need the js-yaml package. I'm going to show you how to use that package to convert a YAML input file to JSON. Then you can use the result with ajv to validate it against a schema.

To install those packages, run this command:

npm install --save ajv js-yaml

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';
import * as yaml from 'js-yaml';

const ajv = new Ajv();

export function parser(inputYamlFile, schemaJsonFile) {

// define a function to read utf8 files
const readUtf8 = (file) => readFileSync(file, 'utf8');

// convert input yaml file to json
const inputJson = yaml.load(readUtf8(inputYamlFile));

// load schema json file
const schemaJson = JSON.parse(readUtf8(schemaJsonFile));

// validate input json against schema json
const isValid = ajv.validate(schemaJson, inputJson);

// return response and errors (if any)
return [isValid, ajv.errors];
}

The code does the following:

  • imports the readFileSync function from the NodeJS fs library
  • imports from the Ajv package
  • imports from the js-yaml package as yaml
  • creates a new object instance (ajv) of the Ajv package
  • defines a function called parser that takes two arguments: an input YAML file and a schema JSON file
  • defines an arrow function within the parent function to read utf-8 (text) files
  • reads the YAML file and converts it to JSON using the js-yaml library
  • reads in the schema JSON as well
  • passes the two JSON objects to the avj.validate method
  • returns two values as an array - the boolean returned by the validate method and the errors, if any

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() {

const [, , ...args] = process.argv;

if (args.length < 2) {
console.log('USAGE: node index.js (file).yaml (schema).json');
return;
}

const [inputYamlFile, schemaJsonFile] = args;

console.log(`input file: ${inputYamlFile}`);
console.log(`schema file: ${schemaJsonFile}`);

const [isValid, err] = parser(inputYamlFile, schemaJsonFile);

console.log(isValid)

if (err) {
console.error(`[ERROR] input not valid!`);
console.error(JSON.stringify(err, null, 2));
return;
}

if( isValid ) {
console.info('[INFO] Valid!');
}
}

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 ignored ([, , ...])
  • the args list variable is assigned the remaining arguments, which should be the input YAML file path and the schema JSON file path
  • if args does not contain at least two items, a usage statement is echoed to the console and the function returns
  • otherwise, the inputYamlFile and schemaJsonFile values are set from args and their paths are echoed to the console
  • the parser method is called, passing in the inputYamlFile and the schemaJsonFile values
  • the return values are assigned to the variables isValid and err
  • if err is not undefined, the error will be echoed to the console and the function will return
  • if isValid is true, then the parser succeeded and a valid message is echoed to the screen

If validation failed, the error will most likely be defined.  So there is no need to check if isValid is false.  I could have written the function to just return the error, implying that if it's undefined, validation succeeded.  But I decided to include the actual flag returned by the ajv.validate method to be thorough.

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 schema code above does the following:

  • defines a JSON object to represent the schema by enclosing the whole thing in brackets
  • the schema is written to be parsed properly by the Ajv package
  • 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 valid input files

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

foo: 1
bar: abc

Based on the schema, this file should pass validation.

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

foo: 1
bar: "abc"

Based on the schema, this file should also pass validation.

Step 10. Test the input files against the schema

In a terminal window, from the root of your project do the following:

node index.js test-files/good.yaml test-files/schema.json

The file should pass validation.

Now check the other valid input file:

node index.js test-files/pretty.yaml test-files/schema.json

This file should also pass validation.

Step 11. Test a file that will fail validation

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

foox: 1
bar: abc

In a terminal window, from the root of your project do the following:

node index.js test-files/bad.yaml 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.yaml 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 structure depending on the file type. That is different from failing validation against a particular schema.

Example Repo

You can find the source for this article here:

Conclusion

In this article, you learned how to validate a YAML file against a JSON schema.

Now you can start writing programs that parse YAML requests, input and configuration files, and alert the user if the format is incorrect.

By converting an input YAML file to JSON, you can use familiar tools like ajv to validate against a JSON formatted schema.

For more information, I’ve included references below.

References