daelynj
daelynj

Reputation: 31

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

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.

Upvotes: 3

Views: 3654

Answers (0)

Related Questions