node.jsopenapiajv

OpenApi schema validation with ajv


I used to validate the response body against the piece of the OpenAPI schema (I parsed the schema file and took only the needed response schema).

But when the response schema references another components.schema (from the same file) - it won't work. I've read this doc about combining schemas: https://ajv.js.org/guide/combining-schemas.html

But it's not clear how to work with multiple references/schemas.

It looks like the "ajv" library cannot work with the whole OpenAPI schema object (Error: strict mode: unknown keyword: "openapi").

Is the whole OpenAPI schema validation possible at all? How do I combine more than 2 schemas (if there are many references)?

Currently I'm trying to combine at least 2 schemas and I'm getting the resolve reference error:

can't resolve reference testObject.json#/schemas/testObject from id http://example.com/schemas/searchResults.json

Here's my test file (it's a piece of the OpenAPI to test only this specific reference case):

## test.spec.yaml    
    schemas:
        testObject:
          $id: http://example.com/schemas/testObject.json
          type: object
          properties:
            prop1:
              type: string
        searchResults:
          $id: http://example.com/schemas/searchResults.json
          type: object
          properties:
            testObjects:
              type: array
              items:
                $ref: "testObject.json#/schemas/testObject"

Here's my code:

import * as fs from "fs";

import Ajv from "ajv";
import * as yaml from "js-yaml";

describe("test", () => {
  it("should validate the openapi schema", async () => {
    const schema: any = yaml.load(fs.readFileSync("test.spec.yaml", "utf8"));

    const a = schema.schemas.searchResults;
    const b = schema.schemas.testObject;

    const ajv = new Ajv({
      strict: true,
      allErrors: true,
      verbose: false,
      schemas: [a, b],
    });

    const validate: any = ajv.getSchema(
      "http://example.com/schemas/searchResults.json"
    );
    const valid = validate({ testObjects: "foo" });
    if (!valid) throw new Error(JSON.stringify(validate.errors));
  });
});

Solution

  • Ok, after some investigation I realized the ajv doesn't work with openapi schema format and it needs some efforts to prepare JSONs out of OpenApi schemas which might be tricky when it comes to working with refs and nesting.

    As for my example, there were 2 issues:

    1. $ref: "testObject.json#/schemas/testObject" -> incorrect. It should be something like "testObject.json#/definitionId"
    2. The structure of the definition should be different, as in this example from docs:
        const testObject = {
            $id: "http://example.com/schemas/testObject.json",
            definitions: {
                int: {type: "integer"},
                str: {type: "string"},
            },
        }
    

    So I can refer to the exact object, like this: $ref: "testObject.json#/definitions/int"