npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@flagpolejs/json-validator

v0.0.2

Published

Simple JSON validator that is similar to JSON Schema format, but with some simplified format that is more readable

Downloads

2

Readme

json-validator

This validator allows you to test whether a given JSON response matches this defined structure.

The format is very similar to the popular JSON Schema [https://json-schema.org/] format. However, it could be difficult to read and write manually. For basic formats, we can get away with something easier. This library was created to be small in size, not designing for every possible use case (but covering the most common ones), being legible, and able to be manually written.

Getting Started and the Schema

In its simplest form you can just define an object with properties of the JSON property names and strings with the type.

const schema = {
  properties: {
    id: "number",
    firstName: "string",
    lastName: "string",
    isActive: "boolean",
    teams: "array",
  },
};

This would match a JSON body like this:

{
    id: 5,
    firstName: "George",
    lastName: "Brett",
    isActive: false,
    teams: [
        "Kansas City Royals"
    ]
}

Whenever we define a value in our schema as a string, we are defining its type. Technically, we could use a more verbose schema definition for the same thing, like this:

const schema = {
  properties: {
    id: { type: "number" },
    firstName: { type: "string" },
    lastName: { type: "string" },
    isActive: { type: "boolean" },
    teams: { type: "array" },
  },
};

But there really is no point in doing that if we simply want to verify the type.

The above works well for a flat structure, but when we start to get nested with arrays or objects then what? Well the next step is we want to make sure every team listed inside the teams array of our JSON body above is a string. Here's how we can do that.

const schema = {
  properties: {
    id: "number",
    firstName: "string",
    lastName: "string",
    isActive: "boolean",
    teams: {
      type: "array",
      items: "string",
    },
  },
};

For our teams property, we used that object notation check that it was an array with the type property. But we also see the items property. Setting this to a string value will verify that each item in the array is a string. Obviously you could put "number" or "boolean" or whatever other type there in that items property to test that every element in the array is that type.

But what if our JSON structure was more complicated? What if the array contained objects with multiple properties? Let's assume our JSON body is this...

{
    id: 5,
    firstName: "George",
    lastName: "Brett",
    isActive: false,
    teams: [
        {
            name: "Kansas City Royals"
            firstSeason: 1973,
            lastSeason: 1994
        }
    ]
}

We would define this schema like this:

const schema = {
  properties: {
    id: "number",
    firstName: "string",
    lastName: "string",
    isActive: "boolean",
    teams: {
      type: "array",
      items: {
        type: "object",
        properties: {
          name: "string",
          firstSeason: "number",
          lastSeason: "number",
        },
      },
    },
  },
};

So, rather than setting items to a string, this time we set it to another object. This effectively is a nested sub-schema. We could keep going with this as deep as we needed to go.

Alright great. George Brett is long retired, so he has a firstSeason and lastSeason property. However, let's say in our schema that if a player is currently active the lastSeason property will be absent from the response. We still want to make sure that if it is present it is a number. But we don't want our schema to fail if it's not there.

This is where the optional property comes in.

const schema = {
  properties: {
    id: "number",
    firstName: "string",
    lastName: "string",
    isActive: "boolean",
    teams: {
      type: "array",
      items: {
        type: "object",
        properties: {
          name: "string",
          firstSeason: "number",
          lastSeason: {
            type: "number",
            optional: true,
          },
        },
      },
    },
  },
};

Well that was easy! Okay, that works when the field is absent for active players. What if lastSeason is always there, but instead it is null when they are still active? No problemo!

const schema = {
  properties: {
    id: "number",
    firstName: "string",
    lastName: "string",
    isActive: "boolean",
    teams: {
      type: "array",
      items: {
        type: "object",
        properties: {
          name: "string",
          firstSeason: "number",
          lastSeason: ["number", "null"],
        },
      },
    },
  },
};

If we set any of our properties to an array of strings, instead of a string, the schema will verify that it is one of those types.

Let's keep amping up the game. Now, rather than just the type, we also want our schema to have an opinion on the actual value. So first, let's start when there are a small set of allowed values. For example, position in baseball. So let's assume our JSON body is this (trimmed it down for simplicity):

{
    id: 5,
    firstName: "George",
    lastName: "Brett",
    positionsPlayed: [ "1b", "3b", "dh" ]
}

We could validate that all of the values in the positionsPlayed array are a valid baseball position.

const schema = {
  properties: {
    id: "number",
    firstName: "string",
    lastName: "string",
    positionsPlayed: {
      type: "array",
      properties: {
        type: "string",
        enum: ["1b", "2b", "ss", "3b", "of", "sp", "rp", "c", "dh"],
      },
    },
  },
};

And that works fine, but baseball players also have numbers on their jersey. But no baseball player is going to have a number over 99, so we want to make sure that it seems valid. Here's our new JSON body:

{
    id: 5,
    firstName: "George",
    lastName: "Brett",
    jerseyNumber: 5
}

So let's use a regular expression to verify the jerseyNumber.

const schema = {
  properties: {
    id: "number",
    firstName: "string",
    lastName: "string",
    jerseyNumber: {
      type: "number",
      pattern: /^[0-9]{1,2}$/,
    },
  },
};

We could have also done this with another property which is test. This property is a function that allows you to run whatever kind of logic you want. So let's change our last one to use a test callback instead.

const schema = {
  properties: {
    id: "number",
    firstName: "string",
    lastName: "string",
    jerseyNumber: {
      type: "number",
      test: function (value) {
        return value >= 0 && value < 100;
      },
    },
  },
};

Obviously using the test function you could get more complicated with your logic. Besides the first value argument called above, the test method also receives a second opts argument. This contains the following properties:

  • path = The path of the current item
  • parent = The last parent item, which would be the array or object this propert is a part of
  • root = The root document that we are evaluating

This allows us to potentially look back at previous values to make sure the current one makes sense relative to the others. For example, it would not make sense for firstSeason to be after lastSeason. So let's test that.

Here's the JSON structure that we are testing:

{
    id: 5,
    firstName: "George",
    lastName: "Brett",
    firstSeason: 1973,
    lastSeason: 1994
}

We will apply this schema to be sure the season years are valid:

const schema = {
    properties: {
        id: "number",
        firstName: "string",
        lastName: "string",
        firstSeason: "number",
        lastSeason: {
            type: [ "number", "null" ]
            test: function(value, opts) {
                return (
                    value === null ||
                    value >= opts.parent.firstSeason
                );
            }
        }
    }
}

JsonValidator

This is a class that allows you to validate a schema.

The constructor accepts the schema and JSON document to be evaluated.

const personSchema: Schema = {
  properties: {
    id: "number",
    firstName: "string",
    lastName: "string",
  },
};
const jsonBody = {
  id: 234,
  firstName: "Karl",
  lastName: "Snyder",
};

const validator = new JsonValidator.validate(schema, jsonBody);
if (validator.isValid) {
  console.log("Valid!");
} else {
  console.log(validator.errors);
}

Static Method

JsonValidator.validate(schema: any, root: any): JsonValidator

Creates a new instance of JsonValidator and runs the validate method on it. This is shorthand.

Properties

errors: ValidationError[]

Gives you the list of errors encountered during the validation process. This will be empty until the validate() method is run.

isValid: boolean

Whether the document was true or false. Note: If validate() has not been run yet, this will always be true.

Methods

validate(schema: any, root: any): JsonValidator

Executes the validation process.