const Ajv = require("ajv/dist/2020")
const addFormats = require('ajv-formats')
const ajv = new Ajv({
allErrors: true,
validateFormats: false,
strictSchema: false,
strictTypes: false})
addFormats(ajv);
const schema = {
"$id": "https://spec.openapis.org/oas/3.1/schema/2021-05-20",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"openapi": {
"type": "string",
"pattern": "^3\\.1\\.\\d+(-.+)?quot;
},
"info": {
"$ref": "#/$defs/info"
},
"jsonSchemaDialect": {
"type": "string",
"format": "uri",
"default": "https://spec.openapis.org/oas/3.1/dialect/base"
},
"servers": {
"type": "array",
"items": {
"$ref": "#/$defs/server"
}
},
"paths": {
"$ref": "#/$defs/paths"
},
"webhooks": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/path-item-or-reference"
}
},
"components": {
"$ref": "#/$defs/components"
},
"security": {
"type": "array",
"items": {
"$ref": "#/$defs/security-requirement"
}
},
"tags": {
"type": "array",
"items": {
"$ref": "#/$defs/tag"
}
},
"externalDocs": {
"$ref": "#/$defs/external-documentation"
}
},
"required": ["openapi", "info"],
"anyOf": [
{
"required": ["paths"]
},
{
"required": ["components"]
},
{
"required": ["webhooks"]
}
],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false,
"$defs": {
"info": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"summary": {
"type": "string"
},
"description": {
"type": "string"
},
"termsOfService": {
"type": "string"
},
"contact": {
"$ref": "#/$defs/contact"
},
"license": {
"$ref": "#/$defs/license"
},
"version": {
"type": "string"
}
},
"required": ["title", "version"],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"contact": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"url": {
"type": "string"
},
"email": {
"type": "string"
}
},
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"license": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"identifier": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri"
}
},
"required": ["name"],
"oneOf": [
{
"required": ["identifier"]
},
{
"required": ["url"]
}
],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"server": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri-reference"
},
"description": {
"type": "string"
},
"variables": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/server-variable"
}
}
},
"required": ["url"],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"server-variable": {
"type": "object",
"properties": {
"enum": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1
},
"default": {
"type": "string"
},
"descriptions": {
"type": "string"
}
},
"required": ["default"],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"components": {
"type": "object",
"properties": {
"schemas": {
"type": "object",
"additionalProperties": {
"$dynamicRef": "#meta"
}
},
"responses": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/response-or-reference"
}
},
"parameters": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/parameter-or-reference"
}
},
"examples": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/example-or-reference"
}
},
"requestBodies": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/request-body-or-reference"
}
},
"headers": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/header-or-reference"
}
},
"securitySchemes": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/security-scheme-or-reference"
}
},
"links": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/link-or-reference"
}
},
"callbacks": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/callbacks-or-reference"
}
},
"pathItems": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/path-item-or-reference"
}
}
},
"patternProperties": {
"^(schemas|responses|parameters|examples|requestBodies|headers|securitySchemes|links|callbacks|pathItems)quot;: {
"$comment": "Enumerating all of the property names in the regex above is necessary for unevaluatedProperties to work as expected",
"propertyNames": {
"pattern": "^[a-zA-Z0-9._-]+quot;
}
}
},
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"paths": {
"type": "object",
"patternProperties": {
"^/": {
"$ref": "#/$defs/path-item"
}
},
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"path-item": {
"type": "object",
"properties": {
"summary": {
"type": "string"
},
"description": {
"type": "string"
},
"servers": {
"type": "array",
"items": {
"$ref": "#/$defs/server"
}
},
"parameters": {
"type": "array",
"items": {
"$ref": "#/$defs/parameter-or-reference"
}
}
},
"patternProperties": {
"^(get|put|post|delete|options|head|patch|trace)quot;: {
"$ref": "#/$defs/operation"
}
},
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"path-item-or-reference": {
"if": {
"required": ["$ref"]
},
"then": {
"$ref": "#/$defs/reference"
},
"else": {
"$ref": "#/$defs/path-item"
}
},
"operation": {
"type": "object",
"properties": {
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"summary": {
"type": "string"
},
"description": {
"type": "string"
},
"externalDocs": {
"$ref": "#/$defs/external-documentation"
},
"operationId": {
"type": "string"
},
"parameters": {
"type": "array",
"items": {
"$ref": "#/$defs/parameter-or-reference"
}
},
"requestBody": {
"$ref": "#/$defs/request-body-or-reference"
},
"responses": {
"$ref": "#/$defs/responses"
},
"callbacks": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/callbacks-or-reference"
}
},
"deprecated": {
"default": false,
"type": "boolean"
},
"security": {
"type": "array",
"items": {
"$ref": "#/$defs/security-requirement"
}
},
"servers": {
"type": "array",
"items": {
"$ref": "#/$defs/server"
}
}
},
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"external-documentation": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri"
}
},
"required": ["url"],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"parameter": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"in": {
"enum": ["query", "header", "path", "cookie"]
},
"description": {
"type": "string"
},
"required": {
"default": false,
"type": "boolean"
},
"deprecated": {
"default": false,
"type": "boolean"
},
"allowEmptyValue": {
"default": false,
"type": "boolean"
},
"schema": {
"$dynamicRef": "#meta"
},
"content": {
"$ref": "#/$defs/content"
}
},
"required": ["in"],
"oneOf": [
{
"required": ["schema"]
},
{
"required": ["content"]
}
],
"dependentSchemas": {
"schema": {
"properties": {
"style": {
"type": "string"
},
"explode": {
"type": "boolean"
},
"allowReserved": {
"default": false,
"type": "boolean"
}
},
"allOf": [
{
"$ref": "#/$defs/examples"
},
{
"$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-path"
},
{
"$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-header"
},
{
"$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-query"
},
{
"$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-cookie"
},
{
"$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-form"
}
],
"$defs": {
"styles-for-path": {
"if": {
"properties": {
"in": {
"const": "path"
}
},
"required": ["in"]
},
"then": {
"properties": {
"style": {
"default": "simple",
"enum": ["matrix", "label", "simple"]
},
"required": {
"const": true
}
},
"required": ["required"]
}
},
"styles-for-header": {
"if": {
"properties": {
"in": {
"const": "header"
}
},
"required": ["in"]
},
"then": {
"properties": {
"style": {
"default": "simple",
"enum": ["simple"]
}
}
}
},
"styles-for-query": {
"if": {
"properties": {
"in": {
"const": "query"
}
},
"required": ["in"]
},
"then": {
"properties": {
"style": {
"default": "form",
"enum": [
"form",
"spaceDelimited",
"pipeDelimited",
"deepObject"
]
}
}
}
},
"styles-for-cookie": {
"if": {
"properties": {
"in": {
"const": "cookie"
}
},
"required": ["in"]
},
"then": {
"properties": {
"style": {
"default": "form",
"enum": ["form"]
}
}
}
},
"styles-for-form": {
"if": {
"properties": {
"style": {
"const": "form"
}
},
"required": ["style"]
},
"then": {
"properties": {
"explode": {
"default": true
}
}
},
"else": {
"properties": {
"explode": {
"default": false
}
}
}
}
}
}
},
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"parameter-or-reference": {
"if": {
"required": ["$ref"]
},
"then": {
"$ref": "#/$defs/reference"
},
"else": {
"$ref": "#/$defs/parameter"
}
},
"request-body": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"content": {
"$ref": "#/$defs/content"
},
"required": {
"default": false,
"type": "boolean"
}
},
"required": ["content"],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"request-body-or-reference": {
"if": {
"required": ["$ref"]
},
"then": {
"$ref": "#/$defs/reference"
},
"else": {
"$ref": "#/$defs/request-body"
}
},
"content": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/media-type"
},
"propertyNames": {
"format": "media-range"
}
},
"media-type": {
"type": "object",
"properties": {
"schema": {
"$dynamicRef": "#meta"
},
"encoding": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/encoding"
}
}
},
"allOf": [
{
"$ref": "#/$defs/specification-extensions"
},
{
"$ref": "#/$defs/examples"
}
],
"unevaluatedProperties": false
},
"encoding": {
"type": "object",
"properties": {
"contentType": {
"type": "string",
"format": "media-range"
},
"headers": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/header-or-reference"
}
},
"style": {
"default": "form",
"enum": ["form", "spaceDelimited", "pipeDelimited", "deepObject"]
},
"explode": {
"type": "boolean"
},
"allowReserved": {
"default": false,
"type": "boolean"
}
},
"allOf": [
{
"$ref": "#/$defs/specification-extensions"
},
{
"$ref": "#/$defs/encoding/$defs/explode-default"
}
],
"unevaluatedProperties": false,
"$defs": {
"explode-default": {
"if": {
"properties": {
"style": {
"const": "form"
}
},
"required": ["style"]
},
"then": {
"properties": {
"explode": {
"default": true
}
}
},
"else": {
"properties": {
"explode": {
"default": false
}
}
}
}
}
},
"responses": {
"type": "object",
"properties": {
"default": {
"$ref": "#/$defs/response-or-reference"
}
},
"patternProperties": {
"^[1-5][0-9X]{2}quot;: {
"$ref": "#/$defs/response-or-reference"
}
},
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"response": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"headers": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/header-or-reference"
}
},
"content": {
"$ref": "#/$defs/content"
},
"links": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/link-or-reference"
}
}
},
"required": ["description"],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"response-or-reference": {
"if": {
"required": ["$ref"]
},
"then": {
"$ref": "#/$defs/reference"
},
"else": {
"$ref": "#/$defs/response"
}
},
"callbacks": {
"type": "object",
"$ref": "#/$defs/specification-extensions",
"additionalProperties": {
"$ref": "#/$defs/path-item-or-reference"
}
},
"callbacks-or-reference": {
"if": {
"required": ["$ref"]
},
"then": {
"$ref": "#/$defs/reference"
},
"else": {
"$ref": "#/$defs/callbacks"
}
},
"example": {
"type": "object",
"properties": {
"summary": {
"type": "string"
},
"description": {
"type": "string"
},
"value": true,
"externalValue": {
"type": "string",
"format": "uri"
}
},
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"example-or-reference": {
"if": {
"required": ["$ref"]
},
"then": {
"$ref": "#/$defs/reference"
},
"else": {
"$ref": "#/$defs/example"
}
},
"link": {
"type": "object",
"properties": {
"operationRef": {
"type": "string",
"format": "uri-reference"
},
"operationId": true,
"parameters": {
"$ref": "#/$defs/map-of-strings"
},
"requestBody": true,
"description": {
"type": "string"
},
"body": {
"$ref": "#/$defs/server"
}
},
"oneOf": [
{
"required": ["operationRef"]
},
{
"required": ["operationId"]
}
],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"link-or-reference": {
"if": {
"required": ["$ref"]
},
"then": {
"$ref": "#/$defs/reference"
},
"else": {
"$ref": "#/$defs/link"
}
},
"header": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"required": {
"default": false,
"type": "boolean"
},
"deprecated": {
"default": false,
"type": "boolean"
},
"allowEmptyValue": {
"default": false,
"type": "boolean"
}
},
"dependentSchemas": {
"schema": {
"properties": {
"style": {
"default": "simple",
"enum": ["simple"]
},
"explode": {
"default": false,
"type": "boolean"
},
"allowReserved": {
"default": false,
"type": "boolean"
},
"schema": {
"$dynamicRef": "#meta"
}
},
"$ref": "#/$defs/examples"
},
"content": {
"properties": {
"content": {
"$ref": "#/$defs/content"
}
}
}
},
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"header-or-reference": {
"if": {
"required": ["$ref"]
},
"then": {
"$ref": "#/$defs/reference"
},
"else": {
"$ref": "#/$defs/header"
}
},
"tag": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"externalDocs": {
"$ref": "#/$defs/external-documentation"
}
},
"required": ["name"],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"reference": {
"type": "object",
"properties": {
"$ref": {
"type": "string",
"format": "uri-reference"
},
"summary": {
"type": "string"
},
"description": {
"type": "string"
}
},
"unevaluatedProperties": false
},
"schema": {
"$dynamicAnchor": "meta",
"type": ["object", "boolean"]
},
"security-scheme": {
"type": "object",
"properties": {
"type": {
"enum": ["apiKey", "http", "mutualTLS", "oauth2", "openIdConnect"]
},
"description": {
"type": "string"
}
},
"required": ["type"],
"allOf": [
{
"$ref": "#/$defs/specification-extensions"
},
{
"$ref": "#/$defs/security-scheme/$defs/type-apikey"
},
{
"$ref": "#/$defs/security-scheme/$defs/type-http"
},
{
"$ref": "#/$defs/security-scheme/$defs/type-http-bearer"
},
{
"$ref": "#/$defs/security-scheme/$defs/type-oauth2"
},
{
"$ref": "#/$defs/security-scheme/$defs/type-oidc"
}
],
"unevaluatedProperties": false,
"$defs": {
"type-apikey": {
"if": {
"properties": {
"type": {
"const": "apiKey"
}
},
"required": ["type"]
},
"then": {
"properties": {
"name": {
"type": "string"
},
"in": {
"enum": ["query", "header", "cookie"]
}
},
"required": ["name", "in"]
}
},
"type-http": {
"if": {
"properties": {
"type": {
"const": "http"
}
},
"required": ["type"]
},
"then": {
"properties": {
"scheme": {
"type": "string"
}
},
"required": ["scheme"]
}
},
"type-http-bearer": {
"if": {
"properties": {
"type": {
"const": "http"
},
"scheme": {
"const": "bearer"
}
},
"required": ["type", "scheme"]
},
"then": {
"properties": {
"bearerFormat": {
"type": "string"
}
},
"required": ["scheme"]
}
},
"type-oauth2": {
"if": {
"properties": {
"type": {
"const": "oauth2"
}
},
"required": ["type"]
},
"then": {
"properties": {
"flows": {
"$ref": "#/$defs/oauth-flows"
}
},
"required": ["flows"]
}
},
"type-oidc": {
"if": {
"properties": {
"type": {
"const": "openIdConnect"
}
},
"required": ["type"]
},
"then": {
"properties": {
"openIdConnectUrl": {
"type": "string",
"format": "uri"
}
},
"required": ["openIdConnectUrl"]
}
}
}
},
"security-scheme-or-reference": {
"if": {
"required": ["$ref"]
},
"then": {
"$ref": "#/$defs/reference"
},
"else": {
"$ref": "#/$defs/security-scheme"
}
},
"oauth-flows": {
"type": "object",
"properties": {
"implicit": {
"$ref": "#/$defs/oauth-flows/$defs/implicit"
},
"password": {
"$ref": "#/$defs/oauth-flows/$defs/password"
},
"clientCredentials": {
"$ref": "#/$defs/oauth-flows/$defs/client-credentials"
},
"authorizationCode": {
"$ref": "#/$defs/oauth-flows/$defs/authorization-code"
}
},
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false,
"$defs": {
"implicit": {
"type": "object",
"properties": {
"authorizationUrl": {
"type": "string"
},
"refreshUrl": {
"type": "string"
},
"scopes": {
"$ref": "#/$defs/map-of-strings"
}
},
"required": ["authorizationUrl", "scopes"],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"password": {
"type": "object",
"properties": {
"tokenUrl": {
"type": "string"
},
"refreshUrl": {
"type": "string"
},
"scopes": {
"$ref": "#/$defs/map-of-strings"
}
},
"required": ["tokenUrl", "scopes"],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"client-credentials": {
"type": "object",
"properties": {
"tokenUrl": {
"type": "string"
},
"refreshUrl": {
"type": "string"
},
"scopes": {
"$ref": "#/$defs/map-of-strings"
}
},
"required": ["tokenUrl", "scopes"],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
},
"authorization-code": {
"type": "object",
"properties": {
"authorizationUrl": {
"type": "string"
},
"tokenUrl": {
"type": "string"
},
"refreshUrl": {
"type": "string"
},
"scopes": {
"$ref": "#/$defs/map-of-strings"
}
},
"required": ["authorizationUrl", "tokenUrl", "scopes"],
"$ref": "#/$defs/specification-extensions",
"unevaluatedProperties": false
}
}
},
"security-requirement": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"specification-extensions": {
"patternProperties": {
"^x-": true
}
},
"examples": {
"properties": {
"example": true,
"examples": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/example-or-reference"
}
}
}
},
"map-of-strings": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
const validate = ajv.compile(schema)
test({
"openapi": "3.1.0",
"info": {
"title": "Webhook Example",
"version": "1.0.0"
},
"webhooks": {
"newPet": {
"post": {
"requestBody": {
"description": "Information about a new pet in the system",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Pet"
}
}
}
},
"responses": {
"200": {
"description": "Return a 200 status to indicate that the data was received successfully"
}
}
}
}
},
"components": {
"schemas": {
"Pet": {
"required": [
"id",
"name"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
}
}
}
}
)
function test(data) {
const valid = validate(data)
if (valid) console.log("Valid!")
else console.log("Invalid: " + ajv.errorsText(validate.errors))
}