How to validate against an OpenAPI schema with $refs using json-schema-validator

2.9k views Asked by At

One caveat here is that the OpenAPI Schema is not being used for the purposes of validating requests and responses. The OpenAPI schema can't be changed to a regular JSON Schema.

Say we have an OpenAPI schema in the form

TestSchema.json

{
  "components": {
    "schemas": {
      "book": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "author": {
            "$ref": "#/components/schemas/author"
          }
        }
      },
      "author": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          }
        }
      }
    }
  }
}

Now imagine we have some JSON taking the form of a "book" as defined in the above schema

{
  "title": "LOTR",
  "author": {
    "name": "Tolkien"
  }
}

Using the json-schema-validator library we've written code to perform this validation as follows

public class SchemaValidator {
    private final ObjectMapper mapper = new ObjectMapper();
    private final JsonSchema schema;

    public SchemaValidator(FileReader schemaFile) throws IOException {
        schema = getJsonSchemaFromJsonNode(mapper.readTree(schemaFile));
    }

    public Set<ValidationMessage> validate(String json) throws IOException {
        return schema.validate(mapper.readTree(json));
    }

    private JsonSchema getJsonSchemaFromJsonNode(JsonNode node) {
        return JsonSchemaFactory.getInstance(VersionFlag.V6).getSchema(node);
    }
}

Usage:

@Test
void validate_invalidTitle() throws IOException {
    var schemaValidator = new SchemaValidator(
        new FileReader("src/test/resources/TestSchema.json")
    );
    var json = "{\"title\":5,\"author\":{\"name\":\"Tolkien\"}}";

    assertEquals(
        "$.title: integer found, string expected",
        schemaValidator.validate(json).stream().findAny().orElseThrow().getMessage()
    );
}

Since the OpenAPI schema has two extra nodes, "components" and "schemas" this code doesn't perform validation because we can't do a 1-1 validation between our "book" json and the schema.

A way around this is to re-write the constructor with a .findValue("book")

public SchemaValidator(FileReader schemaFile) throws IOException {
    schema = getJsonSchemaFromJsonNode(mapper.readTree(schemaFile).findValue("book"));
}

But this results in an error of

#/properties/author/$ref: Reference #/components/schemas/author cannot be resolved

As we have now broken the reference path.

One way around this to get the test to pass is to adjust the $ref in the schema to #/author but the schema itself is then invalid.

Am I missing a tool in this library or building the objects incorrectly? What needs to be done to make this validation work?

I dug around in the open-api-validator which ends up using the json-schema-validator library to perform validation but the request/response validation is not a step I need.

0

There are 0 answers