javascriptyamlschemaopenapiajv

Use Ajv to validate OpenAPI component schemas


I am getting an error when using Ajv to load a schema that uses $ref imported from a yaml file inside an OpenAPI description.

This is my yaml file:

    openapi: 3.0.3
    info:
      title: Demo
      version: 1.0.0
    paths:
      /carousel:
        get:
          responses:
            "200":
              description: Successful operation
              content:
                application/json:
                  schema:
                    type: array
                    items:
                      $ref: "#/components/schemas/test"
    components:
      schemas:
        other:
          type: object
          properties:
            component:
              type: object
        test:
          type: object
          properties:
            slides:
              type: array
              items:
                type: object
                properties:
                  contents:
                    type: array
                    items:
                      anyOf:
                        - $ref: "#/components/schemas/other"

This is my code (JS + Vite)

    import Ajv from 'ajv'
    import YamlContent from '../Config/API.yaml'; //vite.config.js with package @modyfi/vite-plugin-yaml
    const validate =
      new Ajv({
        schemas: YamlContent.components.schemas
      }).
      getSchema(YamlContent.components.schemas.test);

I also tried:

    const validate =
      new Ajv().
      addSchema(YamlContent.components.schemas.other).
      compile(YamlContent.components.schemas.test);

But it always gives the same error. What am i missing here? Thanks.


Solution

  • no reason to use anyOf for a single schema, just pass that schema as the reference

    API.yaml

    openapi: 3.0.3
    info:
      title: Demo
      version: 1.0.0
    paths:
      /carousel:
        get:
          responses:
            "200":
              description: Successful operation
              content:
                application/json:
                  schema:
                    type: array
                    items:
                      $ref: "#/components/schemas/test"
    components:
      schemas:
        other:
          type: object
          properties:
            component:
              type: object
        test:
          type: object
          properties:
            slides:
              type: array
              items:
                type: object
                properties:
                  contents:
                    type: array
                    items:
                      $ref: "#/components/schemas/other"
    

    OpenAPI 3.0.x requires the use of ajv-draft-04 and the ajv-formats packages.

    Because you are using a yaml file, you need a way to load it with js-yaml

    package.json

    {
        "dependencies": {
            "ajv": "^8",
            "ajv-draft-04": "^1.0.0",
            "js-yaml": "^4.1.0",
            "ajv-formats": "^2.1.1"
        }
    }
    

    We use strict:false to make sure the ajv validator abides by the JSON Schema specification correctly.

    The idea is to use the addSchema() method to add the entire OpenAPI description; then use the validate function and provide an object schema with a $ref to the component schema you want to validate against in the first argument and pass the data instance as the second argument. Then output the results.

    index.js

    const Ajv = require('ajv-draft-04')
    const addFormats = require('ajv-formats')
    const fs = require('fs')
    const { load } = require('js-yaml')
    const openapiDescription = load(fs.readFileSync('./Config/API.yaml'))
    
    const testData = {
        "slides": [
            {
                "contents":
                    [{ "component": {} }]
            }]
    }
    
    try {
        const ajv = new Ajv({ strict: false })
        addFormats(ajv)
    
        ajv.addSchema(openapiDescription, "API.yaml")
    
        let validate = ajv.validate({ "$ref": "API.yaml#/components/schemas/test" }, testData)
    
    
        console.log({
            valid: validate,
            error: ajv.errorsText(validate.errors)
        })
    }
    catch (error) {
        console.error(error.message)
    }