Giter Club home page Giter Club logo

openapi4j's Introduction

Build Status Maintainability Rating Security Rating Coverage

This repository is now archived. I don't have enough spare time to maintain this project (well actually revamp) and follow OAI specs. This project deserves much more that I can give to source code and followers to provide appropriate output.

OpenAPI for java project home

This is the home page of the openapi4j project for Java (Jakarta or JVM platform in general).

openapi4j is a suite of tools, including the following :

  • Open API specification parser and validator.
  • Open API Schema Object validator.
  • JSON reference implementation.
  • Request/response validator against operation.
  • For internal use only, performance project reports some numbers to 'manually' check any improvements or regressions between versions.

Modules

  • Parser allows the (de-)serialization and manipulation of the schema and its validation.
  • Schema validator allows the validation of data against a given schema.
  • Request validator is high level module to manage validation for requests and/or responses against operations. More details in the related project.
  • Request adapters is the repository of specific adapters to wrap requests and responses.

Documentation

The documentation for all modules is available here.

Versioning and compatibility

All modules follow the Semantic Versioning 2.0.0 and are aligned on each release even there's no changes.

<dependency>
    <groupId>org.openapi4j</groupId>
    <artifactId>openapi-[module]</artifactId>
</dependency>

Release version Snapshot version

Snapshot is available for latest valid commit on 'master' branch.

Performance

Check here for some values.

Native compilation (GraalVM)

From version 0.7, the toolset is fully compliant with native compilation (AOT). This was tested with GraalVM 19.3.1. No further configuration or directive is needed to include the modules if available on classpath.

native-image -H:+ReportExceptionStackTraces --no-fallback -jar your-app.jar

FYI, testing runs made don't show much performance improvements but parser module.

Supported versions

The modules currently support the OpenAPI Specification (OAS) version 3.0.x.

OAI 3.1.0 has been released as candidate.
There's too much changes too keep code on same basis and keep a fairly low level of complexity.
As a consequence, OAI 3.1.x support will be made in a version 2 of openapi4j.

As my time is very limited, version 1 should be considered as freezed for now.

See related projects for limitations and issues.

Contributing

Reporting issues, making comments, ... Any help is welcome !

We accept Pull Requests via GitHub. There are some guidelines which will make applying PRs easier for us :

  • Respect the code style and indentation. .editorconfig file is provided to not be worried about this.
  • Create minimal diffs - disable on save actions like reformat source code or organize imports. If you feel the source code should be reformatted create a separate PR for this change.
  • Provide JUnit tests for your changes and make sure your changes don't break anything by running gradlew clean check.
  • Provide a self explanatory but brief commit message with issue reference if any, as it will be reported directly for release changelog.

License

openapi4j and all the modules are released under the Apache 2.0 license. See LICENSE for details.

openapi4j's People

Contributors

aburmeis avatar erosb avatar guidouil avatar llfbandit avatar romacafe avatar smhc avatar swiesend avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

openapi4j's Issues

Validation error on nullable parameters with a format

Describe the bug
A validation error is issued by SchemaValidator when a nullable number property with a format (e.g. double) is null.

To Reproduce

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.openapi4j.core.model.v3.OAI3;
import org.openapi4j.core.validation.ValidationResults;
import org.openapi4j.parser.OpenApi3Parser;
import org.openapi4j.parser.model.v3.OpenApi3;
import org.openapi4j.parser.model.v3.Schema;

import java.nio.file.Files;
import java.nio.file.Path;
import org.openapi4j.schema.validator.ValidationContext;
import org.openapi4j.schema.validator.v3.SchemaValidator;

public class NullableFormatBug {

    public static void main(String[] args) throws Exception {
    String openApi =
              "paths:\n"
            + "  /example:\n"
            + "    post:\n"
            + "      requestBody:\n"
            + "        content:\n"
            + "          'application/json':\n"
            + "            schema:\n"
            + "              $ref: '#/components/schemas/NullableFormat'\n"
            + "      responses:\n"
            + "        '200':\n"
            + "          description: Updated\n"
            + "components:\n"
            + "  schemas:\n"
            + "    NullableFormat:\n"
            + "      type: array\n"
            + "      items:\n"
            + "        type: object\n"
            + "        additionalProperties: false\n"
            + "        properties:\n"
            + "          foo:\n"
            + "            type: number\n"
            + "            format: double\n"
            + "            nullable: true\n";

      Path nullableFormatBug = Files.createTempFile("NullableFormatBug", "");
      Files.write(nullableFormatBug, openApi.getBytes());

      OpenApi3 api = new OpenApi3Parser().parse(nullableFormatBug.toFile(), false);

      Schema schema = api.getPath("/example").getOperation("post")
          .getRequestBody().getContentMediaType("application/json").getSchema();

      JsonNode jsonNode = TreeUtil.toJsonNode(schema);

      ValidationContext<OAI3> validationContext = new ValidationContext<>(api.getContext());
      SchemaValidator schemaValidator = new SchemaValidator(validationContext, "", jsonNode);

      String testData1 =
                "["
                 + "{\n"
                 + "  \"foo\": null\n"
                 + "}"
              + "]";

      ObjectMapper mapper = new ObjectMapper();

      ValidationResults results = new ValidationResults();
      schemaValidator.validate(mapper.readTree(testData1), results);
      if (!results.isValid()) {
        System.out.println(results);
      }
    }
}

The following error is displayed when the above code is run:

Validation error(s) :
.#/components/schemas/NullableFormat.items.foo : Value 'null' does not match format 'double'.

Expected behavior
Expected no validation errors from the above code.

additionalProperties using a $ref are resolved to `false` when calling toNode

Describe the bug
When using a JSON ref, it is not possible to get back the additional properties JSON in the schema

To Reproduce

import com.fasterxml.jackson.databind.JsonNode;
import org.openapi4j.parser.OpenApi3Parser;
import org.openapi4j.parser.model.v3.OpenApi3;
import org.openapi4j.parser.model.v3.Schema;

import java.nio.file.Files;
import java.nio.file.Path;

public class AdditionalPropertiesBug {
    public static void main(String[] args) throws Exception {
        String openApi =
        "components:\n" +
        "  schemas:\n" +
        "    Messages:\n" +
        "      type: object\n" +
        "      additionalProperties:\n" +
        "        $ref: '#/components/schemas/Message'\n" +
        "    Message:\n" +
        "      type: object\n" +
        "      properties:\n" +
        "        code:\n" +
        "          type: integer\n" +
        "        text:\n" +
        "          type: string";

        Path enumBug = Files.createTempFile("", "");
        Files.write(enumBug, openApi.getBytes());

        OpenApi3 api = new OpenApi3Parser().parse(enumBug.toFile(), false);

        Schema schema = api.getComponents().getSchema("Messages");

        JsonNode jsonNode = schema.toNode(api.getContext(), true);

        System.out.println(jsonNode.toPrettyString());
    }
}

The output:

{
  "type" : "object",
  "additionalProperties" : false
}

Expected behavior
The additionalProperties field should be the same as the source document

Additional context
I am attempting to use openapi4j to validate JSON examples, from the OpenAPI document and at runtime using https://github.com/networknt/json-schema-validator, any enumerated integer value currently fails

Allow native compilation with GraalVM

The toolset can be easily compliant with AOT compilation.

Todo:

  • Add reflection configuration for parser models and few exceptions related to Jackson.

Motivations:

  • making extension to Quarkus (don't know if this is possible yet).
  • Extend the toolset to a larger population.

External references via $ref not present in OpenApiParser

Describe the bug
A spec file that references another via $ref will validate the contents of the referenced spec file, but will not integrate the content into the final parser for use .

To Reproduce
Steps to reproduce the behavior:

A file "openapi.json" that references another via path:

  "paths": {
    "/pet/{id}": {
        "$ref": "other.json#/paths/~1pet~1{id}"
     }

And another file "other.json":

  "paths": {
    "/pet/{id}": {
        "get": {
               etc
         }
     }

Then attempt to validate a request against the path.

        //    api = new OpenApi3Parser().parse("openapi.json");
        Path path = api.getPath("/pet/{id}");
        Operation op = path.getOperation("get");
        // error - method "get" not found

Expected behavior
Expect to be able to use the "root" spec file that references other spec files to transparently validate data as though everything was defined in the "root" spec file.

Additional context
I can verify the referenced file is loaded and validated as part of parsing. Errors in the referenced file are detected correctly. However the contents referenced under the path are only available as the original string reference via the 'ref' property.

Fail validation for unknown fields

I am trying to validate an input to a given schema but I would like the validation to fail if there are properties in the input that are not in the schema. Is this possible and if not are you planning to implement it?

Root-level `security` declaration causes deserialization error

Describe the bug
When using a root-level security block, the specification.yaml file can't be parsed correctly and fails with a

Exception in thread "main" org.openapi4j.core.exception.ResolutionException: Failed to load spec at 'file:/.../minimal.yaml'
	at org.openapi4j.parser.OpenApi3Parser.parse(OpenApi3Parser.java:38)
	at org.openapi4j.parser.OpenApi3Parser.parse(OpenApi3Parser.java:19)
	at org.openapi4j.parser.OpenApiParser.parse(OpenApiParser.java:53)
	at org.openapi4j.parser.OpenApiParser.parse(OpenApiParser.java:37)
	at Reproducer.main(Reproducer.java:10)
Caused by: org.openapi4j.core.exception.DecodeException: Failed to decode : Cannot deserialize instance of `org.openapi4j.parser.model.v3.SecurityRequirement` out of START_ARRAY token
 at [Source: (StringReader); line: 15, column: 3] (through reference chain: org.openapi4j.parser.model.v3.OpenApi3["security"])
	at org.openapi4j.core.util.TreeUtil.load(TreeUtil.java:123)
	at org.openapi4j.parser.OpenApi3Parser.parse(OpenApi3Parser.java:35)
	... 4 more

I believe the issue can be resolved by converting the security field in OpenApi3.java to a List<SecurityRequirement>, the same way it's defined in Operation.java.

To Reproduce
Steps to reproduce the behavior:

  1. Use a minimal specification with a root-level security block (see reproducer) and at least one security scheme
  2. Load specification normally (see reproducer)
  3. Observe exception

Expected behavior
I expect the root-level security block to behave the same as the operation-level ones and be parsed without problems.

Additional context
Version used: 0.5
Relevant OpenAPI doc: https://swagger.io/docs/specification/authentication/#security

Reproducer
reproducer.zip

Generate resolved schema from data

Is your feature request related to a problem? Please describe.
This is a nice-to-have idea that I have not seen any other validators do, yet I imagine would be quite useful.

The OpenApi schema is useful for describing an API, but less useful for describing a given instance of data due to the use of 'discriminators'. Discriminators make it impossible to traverse the schema and map it directly to the data.

It would be great to have a way to calculate a resolved schema for a given data object, stripped of all discriminators. Thus you could iterate through the resolved schema to navigate your data without having to re-do and re-invent the discrimination code.

I believe this would be a very useful set of functionality. The particular use I have for it is to make it easier to iterate the data to convert 'strings marked as dates' into actual Java Dates. I also need to identify integers that need to be converted to booleans etc for marshalling from another system.

Describe the solution you'd like

Evaluating 'validate' would also return the resolved schema, with 'anyOf', 'oneOf' etc discriminators stripped from the schema and replaced with the calculated properties. The 'resolved schema' may not be a true OpenApi schema, but something similar.

The net result should allow you to iterate the new 'resolved schema' against the data without having to perform any validation/discrimination yourself.

Describe alternatives you've considered
I am currently using a 'format' custom validator to store 'INFO' validation results. I then iterate these validation results and use the 'crumbs' of the validation messages to determine where in the data the date/date-times exist.

This is perhaps a long-term feature that you may not be interested in supporting immediately. However I do think it is a useful bit of functionality that is above what other projects are offering.

allOf schema validator reports incorrect errors

Describe the bug
When a schema is defined using allOf and each schema referenced defines additionalProperties: false then the schema validator seems to be reporting properties that belong to one of the schemas as additional properties and rejects them as errors.

To Reproduce
The code below produces:

Validation error(s) :
.allOf.additionalProperties : Additional property 'hunts' is not allowed.
import static java.lang.System.exit;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.openapi4j.core.exception.EncodeException;
import org.openapi4j.core.model.v3.OAI3;
import org.openapi4j.core.validation.ValidationResults;
import org.openapi4j.parser.OpenApi3Parser;
import org.openapi4j.parser.model.v3.OpenApi3;
import org.openapi4j.parser.validation.v3.OpenApi3Validator;
import org.openapi4j.schema.validator.ValidationContext;
import org.openapi4j.schema.validator.v3.SchemaValidator;

public class QuickTest {

  public static void main(String[] args) throws Exception {
    String openApi =
        "openapi: \"3.0.0\"\n"
            + "info:\n"
            + "  title: Simple Test API\n"
            + "  version: 0.1\n"
            + "paths:\n"
            + "  /pets:\n"
            + "    patch:\n"
            + "      requestBody:\n"
            + "        content:\n"
            + "          application/json:\n"
            + "            schema:\n"
            + "              $ref: '#/components/schemas/Cat'\n"
            + "      responses:\n"
            + "        '200':\n"
            + "          description: Updated\n"
            + "components:\n"
            + "  schemas:\n"
            + "    Pet:\n"
            + "      type: object\n"
            + "      required:\n"
            + "        - pet_type\n"
            + "      properties:\n"
            + "        pet_type:\n"
            + "          type: string\n"
            + "      discriminator:\n"
            + "        propertyName: pet_type\n"
            + "      additionalProperties: false\n"
            + "    Cat:     # \"Cat\" is a value for the pet_type property (the discriminator value)\n"
            + "      allOf: # Combines the main `Pet` schema with `Cat`-specific properties \n"
            + "        - type: object\n"
            + "          required:\n"
            + "            - pet_type\n"
            + "          properties:\n"
            + "            pet_type:\n"
            + "              type: string\n"
            + "          additionalProperties: false\n"
            + "        - type: object\n"
            + "          additionalProperties: false\n"
            + "          properties:\n"
            + "            hunts:\n"
            + "              type: boolean\n"
            + "            age:\n"
            + "              type: integer\n"
            + "      example:\n"
            + "        {\n"
            + "          \"pet_type\": \"Cat\",\n"
            + "          \"hunts\": false\n"
            + "        }";

    Path bug = Files.createTempFile("SchemaCompositionBug", "");
    Files.write(bug, openApi.getBytes());

    OpenApi3 api = new OpenApi3Parser().parse(bug.toFile(), false);

    OpenApi3Validator.instance().validate(api);

    api.getComponents().getSchemas().values().forEach(schema -> {
      Object example = schema.getExample();
      if (example != null) {
        try {
          final JsonNode dataNode = new ObjectMapper()
              .readTree(new ObjectMapper().writeValueAsBytes(example));
          final JsonNode schemaNode = schema.toNode(api.getContext(), true);
          final ValidationResults results = new ValidationResults();
          final ValidationContext<OAI3> validationContext = new ValidationContext<OAI3>(
              api.getContext()).setFastFail(true);
          final SchemaValidator schemaValidator = new SchemaValidator(validationContext, "",
              schemaNode);
          schemaValidator.validate(dataNode, results);
          if (!results.isValid()) {
            System.err.println(results.toString());
            exit(-1);
          }
        } catch (IOException | EncodeException e) {
          exit(-1);
        }
      }
    });
  }
}

Expected behavior
The above example should produce no validation errors.

Relative url support in OAuthFlow Object

Describe the bug

Relative URLs are not allowed in the authorizationUrl field of the OAuth Flow Object.

Expected behavior

The specification indicates that

Relative References in URLs
Unless specified otherwise, all properties that are URLs MAY be relative references as defined by RFC3986. Relative references are resolved using the URLs defined in the Server Object as a Base URI.

The authorization URL to be used for this flow. This MUST be in the form of a URL.

As there is nothing special about this URL, I guess this field (and others) should be allowed to use relative paths.

What do you think about it ?

Schema composition with discriminator causes validation errors

Describe the bug
Composing schemas using allOf with one of the schemas containing the discriminator property causes validation errors.

To Reproduce

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.file.Files;
import java.nio.file.Path;
import org.openapi4j.core.model.v3.OAI3;
import org.openapi4j.core.validation.ValidationResults;
import org.openapi4j.parser.OpenApi3Parser;
import org.openapi4j.parser.model.v3.OpenApi3;
import org.openapi4j.parser.model.v3.Schema;
import org.openapi4j.parser.validation.v3.OpenApi3Validator;
import org.openapi4j.schema.validator.ValidationContext;
import org.openapi4j.schema.validator.v3.SchemaValidator;

public class SchemaCompositionBug {

  public static void main(String[] args) throws Exception {
    String openApi =
        "paths:\n"
            + "  /pets:\n"
            + "    patch:\n"
            + "      requestBody:\n"
            + "        content:\n"
            + "          application/json:\n"
            + "            schema:\n"
            + "              oneOf:\n"
            + "                - $ref: '#/components/schemas/Cat'\n"
            + "                - $ref: '#/components/schemas/Dog'\n"
            + "              discriminator:\n"
            + "                propertyName: pet_type\n"
            + "      responses:\n"
            + "        '200':\n"
            + "          description: Updated\n"
            + "components:\n"
            + "  schemas:\n"
            + "    Pet:\n"
            + "      type: object\n"
            + "      required:\n"
            + "        - pet_type\n"
            + "      properties:\n"
            + "        pet_type:\n"
            + "          type: string\n"
            + "      discriminator:\n"
            + "        propertyName: pet_type\n"
            + "    Dog:     # \"Dog\" is a value for the pet_type property (the discriminator value)\n"
            + "      allOf: # Combines the main `Pet` schema with `Dog`-specific properties \n"
            + "        - $ref: '#/components/schemas/Pet'\n"
            + "        - type: object\n"
            + "          # all other properties specific to a `Dog`\n"
            + "          properties:\n"
            + "            bark:\n"
            + "              type: boolean\n"
            + "            breed:\n"
            + "              type: string\n"
            + "              enum: [Dingo, Husky, Retriever, Shepherd]\n"
            + "    Cat:     # \"Cat\" is a value for the pet_type property (the discriminator value)\n"
            + "      allOf: # Combines the main `Pet` schema with `Cat`-specific properties \n"
            + "        - $ref: '#/components/schemas/Pet'\n"
            + "        - type: object\n"
            + "          # all other properties specific to a `Cat`\n"
            + "          properties:\n"
            + "            hunts:\n"
            + "              type: boolean\n"
            + "            age:\n"
            + "              type: integer";

    Path bug = Files.createTempFile("SchemaCompositionBug", "");
    Files.write(bug, openApi.getBytes());

    OpenApi3 api = new OpenApi3Parser().parse(bug.toFile(), false);

    OpenApi3Validator.instance().validate(api);
  }
}

Expected behavior
Expected the above to validate with no errors.

Additional context
The Open API definition above is taken from a Swagger example: https://swagger.io/docs/specification/data-models/oneof-anyof-allof-not/#allof

Unable to load refs when parsing with project in jar

I have multiple openapi files in my resources folder that reference each other. Attempting to parse them works just fine when running the code with my IDE, but as soon as I jar the project and run the jar, openapi4j is unable to process any refs. I am loading the swagger file like this:

URL url = Thread.currentThread().getContextClassLoader().getResource(filePath);
openAPI = new OpenApi3Parser().parse(url, false);

and my swagger file looks like this:

{
  "openapi" : "3.0.0",
  "info" : {
    "title" : "My Service",
    "version" : "1.0.0"
  },
  "paths" : {
    "/endpoint" : { "$ref" :  "swagger2.json#/paths/get_endpoint" },
  }
}

To Reproduce

  1. Reference another swagger file from your root swagger file in your project resources
  2. Parse the root file and confirm it works correctly
  3. Create a jar of your project, including resources
  4. Run the jar

Expected behavior
The refs should evaluate, even though they are in a jar

Enum's in Schema are stored as strings

Describe the bug
Enums in the Schema object are stored as a list of String's. This is a problem when converted back to JSON as the original type information is lost, making the schema unusable for schema validation

To Reproduce

import com.fasterxml.jackson.databind.JsonNode;
import org.openapi4j.parser.OpenApi3Parser;
import org.openapi4j.parser.model.v3.OpenApi3;
import org.openapi4j.parser.model.v3.Schema;

import java.nio.file.Files;
import java.nio.file.Path;

public class EnumBug {
    public static void main(String[] args) throws Exception {
        String openApi =
        "paths:\n" +
        "  /items:\n" +
        "    get:\n" +
        "      parameters:\n" +
        "        - in: query\n" +
        "          name: sort\n" +
        "          description: Sort order\n" +
        "          schema:\n" +
        "            type: integer\n" +
        "            enum: [0, 1]";

        Path enumBug = Files.createTempFile("EnumBug", "");
        Files.write(enumBug, openApi.getBytes());

        OpenApi3 api = new OpenApi3Parser().parse(enumBug.toFile(), false);

        Schema schema = api.getPath("/items").getOperation("get").getParameters().get(0).getSchema();

        JsonNode jsonNode = schema.toNode(api.getContext(), false);

        System.out.println(jsonNode.toPrettyString());
    }
}

The output enum contains strings:

{
  "enum" : [ "0", "1" ],
  "type" : "integer"
}

Expected behavior
The output should be an enum of int's

{
  "enum" : [ 0, 1 ],
  "type" : "integer"
}

Additional context
I am attempting to use openapi4j to validate JSON examples, from the OpenAPI document and at runtime using https://github.com/networknt/json-schema-validator, any enumerated integer value currently fails

relative url support in Server Object

Describe the bug
Hi,

url field in Server Object should allow a relative url. But it seems like not supported yet.

from the spec:

A URL to the target host. This URL supports Server Variables and MAY be relative, to indicate that the host location is relative to the location where the OpenAPI document is being served. Variable substitutions will be made when a variable is named in {brackets}.

Operation validator: add request validation from URL only

Is your feature request related to a problem? Please describe.

I would like to validate a request/response by path rather than a known operation id. To validate requests as they arrive to an end-point the only information we have is the path, headers and method. We don't know what the "operation" is. We can do this with code similar to:

Path path = api.getPath(request.getPath());
Operation op = path.getOperation(request.getMethod());
OperationValidator operationValidator = new OperationValidator(ctx, api, path, op);
ValidationResults vr = new ValidationResults();
operationValidator.validateBody(request, vr);

However this only works for paths with no parameters. I would like to find paths such as "/pet/{petId}".

Describe the solution you'd like

I believe the "api.getPath" could take an overload which converts all paths with "{xxx}" to regexes similar to: "/pet/.*/" and find a match using this instead.

It would be nice if it also took the 'servers:url' component into account as well. Perhaps an api.findPath(url) that correctly finds the path by skipping over the server part and regexing through the parameters parts.

Describe alternatives you've considered

I can write my own iteration over the map of paths but it would be nice to have this part of the API. I suspect many people would like to validate using the path+method/response code rather than a known operation id.

Do not follow refs for discriminator properties

Is your feature request related to a problem? Please describe.
When parsing the API we do the following to get a full document with all references inlined:

new OpenApi3Parser().parse(tempFile.toFile, false)
api.copy(api.getContext, true)

The API definition contains multiple schemas with discriminator properties like the one below:

components:
  responses:
    sampleObjectResponse:
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/Object1'
              - $ref: '#/components/schemas/Object2'
              - $ref: 'sysObject.json#/sysObject'
            discriminator:
              propertyName: objectType
              mapping:
                obj1: '#/components/schemas/Object1'
		obj2: '#/components/schemas/Object2'
                system: 'sysObject.json#/sysObject'
  โ€ฆ
  schemas:
    Object1:
      type: object
      required:
        - objectType
      properties:
        objectType:
          type: string
      โ€ฆ
    Object2:
      type: object
      required:
        - objectType
      properties:
        objectType:
          type: string
      โ€ฆ

The problem with flattening the above is that it no longer complies with the OpenAPI specification because discriminator properties must be used in conjunction with a Schema ref and cannot be used with an inline schema.

Validating the above schema with a valid payload fails with a NullPointerException because the DiscriminatorValidator is looking for a schema ref.

Describe the solution you'd like
Do not inline refs if they are used as discriminator properties

Describe alternatives you've considered
At the moment we are working around it by not following refs at the top level and instead selectively following refs on the operation level using Operation::copy.

Validate against discriminator-related "subclass" schemas

When using the allOf pattern with discriminators and referencing only the "superclass" (so to speak) from the operation (see example below,) it would be useful to validate not only against the superclass schema, but also the subclass schema.
I.e. if validating an instance against a schema that has a discriminator field, look for a schema in #/components/schemas that is defined with an allOf that contains a $ref to the original schema, and whose name matches the discriminator value in the instance, and validate against that schema instead.

I'm not sure if this is on the edge of the validator's responsibility or the OpenAPI specification, but it seems reasonable enough. The last paragraph of the description at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#discriminatorObject is a little vague though.

Thoughts?

paths:
  /discriminator:
    post:
      operationId: discriminator
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Pet'
components:
  schemas:
    Pet:
      type: object
      required:
        - pet_type
      properties:
        pet_type:
          type: string
      discriminator:
        propertyName: pet_type
    Dog:     # "Dog" is a value for the pet_type property (the discriminator value)
      allOf: # Combines the main `Pet` schema with `Dog`-specific properties
        - $ref: '#/components/schemas/Pet'
        - type: object
          # all other properties specific to a `Dog`
          properties:
            bark:
              type: boolean
            breed:
              type: string
              enum: [Dingo, Husky, Retriever, Shepherd]
    Cat:     # "Cat" is a value for the pet_type property (the discriminator value)
      allOf: # Combines the main `Pet` schema with `Cat`-specific properties
        - $ref: '#/components/schemas/Pet'
        - type: object
          # all other properties specific to a `Cat`
          properties:
            hunts:
              type: boolean
            age:
              type: integer

Per call context object available to custom validators.

Is your feature request related to a problem? Please describe.
I would like to be able to pass context to the custom validators per call.
I create and store an OperationValidator then call methods such as 'validateBody' on this. However my custom validation ideally needs to know whether it is validating a request or a response.

I can imagine other use cases where someone may want to make available the entire request or response object (or another object entirely) to the validators such that they can use this extra context for validation.

Describe the solution you'd like
Probably the most flexible solution is to support passing a generic 'Object' to the 'validateBody' etc validators which is pass around everywhere.
Alternatively there can be a generic object on "ValidationResults" that is already passed everywhere (will need to ensure this object is also added on any copies that are made in anyOf and oneOf validators).
It might be best to replace the existing ValidationResults with a new wrapper class:

class ValidatingContext
{
   ValidationResults vr;
   
    Object customData;
    // or
    virtual Object getCustomData()
}

Describe alternatives you've considered

  • A possible workaround can be to insert a dummy 'ValidationItem' at index 0 of the validation results. However the anyOf and oneOf validators create new ValidationResults objects for validation so don't have access to it.
  • A singleton - however this is not thread safe.
  • Walking up the schema to determine if there is a 'responseBody' or 'requestBody'.

Additional context
I can help work on a solution if you can give an idea of an approved design.

Map<String,Object> incorrectly validated

Describe the bug
Validating a Map<String,Object> implicitly converts the map to a JsonNode using a schema. However this causes values to be coerced to the correct type. This can mean numbers get converted to strings and validate as strings. It can also cause strings to be parsed as numbers, fail parsing, and be left as 'null'. This causes the validation errors to be incorrect or missing.

The use of a schema for conversion is also problematic as it does not cater for discriminators which can cause values to be converted to different types depending on context.

To Reproduce

spec: 
{
  "properties": {
        "name":  { 
            "type": "string"
         }
   }
}

request body:
{
 name: 1234
}

Validate the body using a Map<String,Object> representation of the request.

Expected behavior

Expect that Java String objects get converted to JsonNode strings, irrespective of the schema. Likewise for Integer etc objects.

This can be worked around by manually converting to JsonNode:

     ObjectMapper OBJECT_MAPPER = new ObjectMapper();
     JsonNode jsonNodeMap = OBJECT_MAPPER.convertValue(objMap, JsonNode.class);
     builder.body(Body.from(jsonNodeMap));

If this is too difficult to solve it may be best to deprecate the Map<String,Object> interface, as it seems quite incorrect.

Parser: nested reference cycling is not detected

This sample below could lead to stack overflows at parsing validation.
Despite the functional validity, the description is correct.

components:
  schemas:
    Self:
      type: object
      properties:
        self:
          $ref: '#/components/schemas/Self'
    Foo:
      type: object
      properties:
        child:
          $ref: '#/components/schemas/Bar'
    Bar:
      type: object
      properties:
        parent:
          $ref: '#/components/schemas/Foo'

ValidateHeaders fails when one httpStatus has headers

Describe the bug
I have one method response (202) with a header. The other responses don't have headers. When I have a 200 response the validator returns:
"Validation error(s) :
Response status '200', ranged or default has not been found. (code: 204)"

To Reproduce
Steps to reproduce the behavior:

  1. API with a method with a response with header and another response with content type
  2. Validate the return of the response with content type
  3. The headers will not validate

Expected behavior
As the API does not declare any header for the response, the response should be valid

Query parameters not marked as required still fail NullableValidator

Describe the bug
Given two query parameters a and b, both not marked as required.
If a request has no query string, it will correctly pass the request validation.
However, a request that has a value for a but not b will fail validation with the message

b.nullable : Null value is not allowed.

To Reproduce
Steps to reproduce the behavior:

  1. Define two or more non-required query parameters
  2. Validate a request with query set to null - it will pass
  3. Validate a request with query set to empty string - it won't pass
  4. Validate a request with query set to a=1 (where a is one of the parameters defined in step 1) - it won't pass

Expected behavior
Given two non-required query parameters, I'd expect a request to pass without specifying a value for all parameters.

Additional context
The issue seems to be caused by ParameterValidator#checkRequired. When the query is null, the paramValues will be an empty map.
However, when the query is "", the paramValues is populated with null-values. Similarly, when the query is a=1, the map will contain the values {a: 1, b: null}
This causes the function to return true, thus marking the null-ish parameter for further validation.
Later on, in the NullishValidator, it's correctly recognized that the query parameter is set to null

One solution could be to treat null values in paramValues as unset.

Reproducer
required-params.zip

Add support for creating an OpenApi3 object from a JsonNode

Is your feature request related to a problem? Please describe.
I am preprocessing my OpenAPI document, by the time I come to parse it with OpenApi3Parser I already have a JsonNode. The current parser requires a file, which means I need to serilaise and write it to disk in order to get a OpenApi3

Describe the solution you'd like
Either add a method to OpenApi3Parser that takes a JsonNode or provide some other utility to do it

Data against Schema validator - $ref, allOf/anyOf/oneOf, nullable $ref objects and nullable enums.

Hey @llfbandit,

your library is great and helps a lot to validate data against a rather complex schema, but I encountered some problems, which I like to share with an example.

My example OpenAPI spec defines a Zoo which contains:

  1. root references like: $ref: "#/components/schemas/???". Which leads to a schemaParentNode/parentSchema problem.
  2. allOf/anyOf quantor for grouped objects, see: BigFive. Which one is to pick, if I want to allow any Animal within that group?
  3. anyOf/oneOf quantor for array items, see: SafariPark.animals. Which one is to pick, if I want to allow any of the given Animals by its group?
  4. nullable referenced objects, as follows (see also Reference objects don't combine well with โ€œnullableโ€ #1368 , Clarify Semantics of nullable in OpenAPI 3.0):

"Sibling values alongside $refs are ignored. To add properties to a $ref, wrap the $ref into allOf, or move the extra properties into the referenced definition (if applicable)." (swagger-editor)

          properties:
            maybeSafari:
              $ref: "#/components/schemas/SafariPark"

-->

    SafariPark:
      type: object
      nullable: true
  1. nullable enums do not work as expected:
        subspecies:
          type: string
          nullable: true
          enum:
            - PantheraLeoLeo
            - PantheraLeoMelanochaita
            - null

I have four problems:

Problem 1:
I guess with the upcoming changes in 0.9 I won't be able to instantiate the SchemaValidator with the schemaParentNode and parentSchema, as this constructor is not public anymore.

I wrote a validation method in Scala like so:

  def validate(schemaName: String, data: JsonNode, isValid: Boolean, schema: JsonNode): ValidationResults = {
    val apiContext: OAI3Context = new OAI3Context(new URI("/"), schema)
    val validationContext: ValidationContext[OAI3] = new ValidationContext(apiContext)
    validationContext.setFastFail(true)

    val parentValidator = new SchemaValidator("", schema)

    // 0.8
    val objectValidator: SchemaValidator = new SchemaValidator(
      validationContext, // context
      schemaName, // propertyName
      Try(schema.get("components").get("schemas").get(schemaName)).getOrElse(schema), // schemaNode
      schema, // schemaParentNode
      parentValidator // parentSchema
    )
    val validation = new ValidationResults();

    // 0.9-SNAPSHOT
    //    val objectValidator: SchemaValidator = new SchemaValidator(
    //      validationContext,
    //      schemaName,
    //      schema.get("components").get("schemas").get(schemaName)
    //    ???
    //    )
    //    val validation: ValidationData[Unit] = new ValidationData();

    objectValidator.validate(data, validation)
    if (validation.isValid === false) println(s"'$schemaName' $validation")
    // assert(validation.isValid === isValid)
    validation
  }

This validates:

"A `Zoo` with a `SafariPark`" should "only contain `BigFive` `Animal`s" in {
    val schema: JsonNode = TreeUtil.json.readTree(new File("zoo.json"))

    val data: JsonNode = TreeUtil.json.readTree(
      """
        |{
        |  "name": "Zoologischer Garten Berlin AG",
        |  "maybeNickname": "Zoo Berlin",
        |  "parks": {
        |    "maybeSafari": {
        |      "name": "Great Safari Park",
        |      "animals": [
        |        {
        |          "species": "LoxodontaAfricana",
        |          "subspecies": null
        |        },
        |        {
        |          "species": "PantheraLeo",
        |          "subspecies": "PantheraLeoLeo"
        |        }
        |      ]
        |    }
        |  }
        |}
        |""".stripMargin)
    val result = validate("Zoo", data, true, schema)
    assert(result.isValid === true)
  }

Problem 2:
If I try at purpose to break the schema, by changing species to a forbidden value, then I get a rather uninformative validation report like this:

'Zoo' Validation error(s) :
Zoo.parks.maybeSafari./#/components/schemas/SafariPark.animals.items.anyOf : No valid schema. (code: 1001)

Problem 3:
nullable referenced objects are not validated as nullables:

"A `Zoo` without a `SafariPark`" should "be valid, too" in {
    val schema: JsonNode = TreeUtil.json.readTree(new File("zoo.json"))

    val data: JsonNode = TreeUtil.json.readTree(
      """
        |{
        |  "name": "Zoologischer Garten Berlin AG",
        |  "maybeNickname": "Zoo Berlin",
        |  "parks": {
        |    "maybeSafari": null
        |  }
        |}
        |""".stripMargin)
    val result = validate("Zoo", data, true, schema)
    assert(result.isValid === true)
  }

Which give me the following validation error:

'Zoo' Validation error(s) :
Zoo.parks.maybeSafari.nullable : Null value is not allowed. (code: 1021)

Problem 4:
This validates fine:

"A valid `Animal` with a nullable enum" should "be valid" in {
    val schema: JsonNode = TreeUtil.json.readTree(new File("zoo.json"))

    val data: JsonNode = TreeUtil.json.readTree(
      """
        |{
        |  "species": "PantheraPardus",
        |  "subspecies": null
        |}
        |""".stripMargin)
    val result = validate("Animal", data, true, schema)
    assert(result.isValid === true)
  }

But this does not, as the validator seems to accept any value, but I expect the enum to forbid such values:

  "An invalid `Animal` with a nullable enum" should "not be valid" in {
    val schema: JsonNode = TreeUtil.json.readTree(new File("zoo.json"))

    val data: JsonNode = TreeUtil.json.readTree(
      """
        |{
        |  "species": "PantheraPardus",
        |  "subspecies": "not allowed"
        |}
        |""".stripMargin)
    val result = validate("Animal", data, false, schema)
    assert(result.isValid === false)
  }

This it the full zoo.yaml:

openapi: 3.0.0
info:
  title: Zootopia
  description: "The zoo is a place where animals are held. Hopefully under good circumstances."
  version: 1.0.0

paths:
  /api/v1/zoo/{name}:
    get:
      parameters:
        - in: path
          name: name
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Ok
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Zoo"

components:
  schemas:
    Zoo:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        maybeNickname:
          type: string
          nullable: true
        parks:
          properties:
            maybeSafari:
              $ref: "#/components/schemas/SafariPark"
              # nullable: true # "Sibling values alongside $refs are ignored. To add properties to a $ref, wrap the $ref into allOf, or move the extra properties into the referenced definition (if applicable)." (swagger-editor)
            # apes:
            # ...
            # birds:
            # ...
            # aquarium:
            # ...

    SafariPark:
      type: object
      nullable: true
      required:
        - name
        - animals
      properties:
        name:
          type: string
        animals:
          type: array
          items:
            anyOf:
              - $ref: "#/components/schemas/BigFive"

    Animal:
      type: object
      required:
        - species
      properties:
        species:
          type: string
        subspecies:
          type: string
          nullable: true
      discriminator:
        propertyName: species
        mapping:
          LoxodontaAfricana: '#/components/schemas/Elephant'
          LoxodontaCyclotis: '#/components/schemas/Elephant'
          DicerosBicornis: '#/components/schemas/Rhinoceros' 
          SyncerusCaffer: '#/components/schemas/CapeBuffalo'
          PantheraLeo: "#/components/schemas/Lion"
          PantheraPardus: "#/components/schemas/Leopard"

    BigFive:
      anyOf:
        - $ref: "#/components/schemas/Elephant"
        - $ref: "#/components/schemas/Rhinoceros"
        - $ref: "#/components/schemas/CapeBuffalo"
        - $ref: "#/components/schemas/Lion"
        - $ref: "#/components/schemas/Leopard"

    Elephant:
      allOf:
        - $ref: '#/components/schemas/Animal'
        - type: object
      properties:
        species:
          enum:
            - LoxodontaAfricana
            - LoxodontaCyclotis

    Rhinoceros:
      allOf:
        - $ref: '#/components/schemas/Animal'
        - type: object
      properties:
        species:
          enum:
            - DicerosBicornis

    CapeBuffalo:
      allOf:
        - $ref: '#/components/schemas/Animal'
        - type: object
      properties:
        species:
          enum:
            - SyncerusCaffer
        subspecies:
          enum:
            - SyncerusCafferCaffer
            - SyncerusCafferNanus
            - SyncerusCafferBrachyceros
            - SyncerusCafferAequinoctialis
            - SyncerusCafferMathewsi
            - null

    Lion:
      allOf:
        - $ref: '#/components/schemas/Animal'
        - type: object
      properties:
        species:
          enum:
            - PantheraLeo
        subspecies:
          enum:
            - PantheraLeoLeo
            - PantheraLeoMelanochaita
            - null
    
    Leopard:
      allOf:
      - $ref: '#/components/schemas/Animal'
      - type: object
      properties:
        species:
          enum:
            - PantheraPardus
        subspecies:
          enum:
            - PantheraPardusPardus
            - null

The zoo.yaml as json (converted with the swagger-editor):

{
  "openapi": "3.0.0",
  "info": {
    "title": "Zootopia",
    "description": "The zoo is a place where animals are held. Hopefully under good circumstances.",
    "version": "1.0.0"
  },
  "paths": {
    "/api/v1/zoo/{name}": {
      "get": {
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Zoo"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Zoo": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "maybeNickname": {
            "type": "string",
            "nullable": true
          },
          "parks": {
            "properties": {
              "maybeSafari": {
                "$ref": "#/components/schemas/SafariPark"
              }
            }
          }
        }
      },
      "SafariPark": {
        "type": "object",
        "nullable": true,
        "required": [
          "name",
          "animals"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "animals": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "$ref": "#/components/schemas/BigFive"
                }
              ]
            }
          }
        }
      },
      "Animal": {
        "type": "object",
        "required": [
          "species"
        ],
        "properties": {
          "species": {
            "type": "string"
          },
          "subspecies": {
            "type": "string",
            "nullable": true
          }
        },
        "discriminator": {
          "propertyName": "species",
          "mapping": {
            "LoxodontaAfricana": "#/components/schemas/Elephant",
            "LoxodontaCyclotis": "#/components/schemas/Elephant",
            "DicerosBicornis": "#/components/schemas/Rhinoceros",
            "SyncerusCaffer": "#/components/schemas/CapeBuffalo",
            "PantheraLeo": "#/components/schemas/Lion",
            "PantheraPardus": "#/components/schemas/Leopard"
          }
        }
      },
      "BigFive": {
        "anyOf": [
          {
            "$ref": "#/components/schemas/Elephant"
          },
          {
            "$ref": "#/components/schemas/Rhinoceros"
          },
          {
            "$ref": "#/components/schemas/CapeBuffalo"
          },
          {
            "$ref": "#/components/schemas/Lion"
          },
          {
            "$ref": "#/components/schemas/Leopard"
          }
        ]
      },
      "Elephant": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Animal"
          },
          {
            "type": "object"
          }
        ],
        "properties": {
          "species": {
            "enum": [
              "LoxodontaAfricana",
              "LoxodontaCyclotis"
            ]
          }
        }
      },
      "Rhinoceros": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Animal"
          },
          {
            "type": "object"
          }
        ],
        "properties": {
          "species": {
            "enum": [
              "DicerosBicornis"
            ]
          }
        }
      },
      "CapeBuffalo": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Animal"
          },
          {
            "type": "object"
          }
        ],
        "properties": {
          "species": {
            "enum": [
              "SyncerusCaffer"
            ]
          },
          "subspecies": {
            "enum": [
              "SyncerusCafferCaffer",
              "SyncerusCafferNanus",
              "SyncerusCafferBrachyceros",
              "SyncerusCafferAequinoctialis",
              "SyncerusCafferMathewsi",
              null
            ]
          }
        }
      },
      "Lion": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Animal"
          },
          {
            "type": "object"
          }
        ],
        "properties": {
          "species": {
            "enum": [
              "PantheraLeo"
            ]
          },
          "subspecies": {
            "enum": [
              "PantheraLeoLeo",
              "PantheraLeoMelanochaita",
              null
            ]
          }
        }
      },
      "Leopard": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Animal"
          },
          {
            "type": "object"
          }
        ],
        "properties": {
          "species": {
            "enum": [
              "PantheraPardus"
            ]
          },
          "subspecies": {
            "enum": [
              "PantheraPardusPardus",
              null
            ]
          }
        }
      }
    }
  }
}

Operator validator: Operation path parameters validation fails if server URL has path parameters/fragments

In case of path parameter setup on server URL, searching for path parameter will fail.

A relative path to an individual endpoint. The field name MUST begin with a slash. The path is appended (no relative URL resolution) to the expanded URL from the Server Object's url field in order to construct the full URL.

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#paths-object

This should be fixed before feature #59

Nullable schema validation error on non-required properties

Describe the bug
Non-required schema properties that are null produce a validation error: NullableFormat.items.foo.nullable : Null value is not allowed.

To Reproduce
Steps to reproduce the behavior:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.openapi4j.core.model.v3.OAI3;
import org.openapi4j.core.util.TreeUtil;
import org.openapi4j.core.validation.ValidationResults;
import org.openapi4j.parser.OpenApi3Parser;
import org.openapi4j.parser.model.v3.OpenApi3;
import org.openapi4j.parser.model.v3.Schema;

import java.nio.file.Files;
import java.nio.file.Path;
import org.openapi4j.schema.validator.ValidationContext;
import org.openapi4j.schema.validator.v3.SchemaValidator;

public class NullableFormatBug {

  public static void main(String[] args) throws Exception {
    String openApi =
        "paths:\n"
            + "  /example:\n"
            + "    post:\n"
            + "      requestBody:\n"
            + "        content:\n"
            + "          'application/json':\n"
            + "            schema:\n"
            + "              $ref: '#/components/schemas/NullableFormat'\n"
            + "      responses:\n"
            + "        '200':\n"
            + "          description: Updated\n"
            + "components:\n"
            + "  schemas:\n"
            + "    NullableFormat:\n"
            + "      type: array\n"
            + "      items:\n"
            + "        type: object\n"
            + "        additionalProperties: false\n"
            + "        properties:\n"
            + "          foo:\n"
            + "            type: number\n"
            + "            format: double\n";

    Path nullableFormatBug = Files.createTempFile("NullableFormatBug", "");
    Files.write(nullableFormatBug, openApi.getBytes());

    OpenApi3 api = new OpenApi3Parser().parse(nullableFormatBug.toFile(), false);

    Schema schema = api.getPath("/example").getOperation("post")
        .getRequestBody().getContentMediaType("application/json").getSchema();

    JsonNode jsonNode = schema.toNode(api.getContext(), true);

    ValidationContext<OAI3> validationContext = new ValidationContext<>(api.getContext());
    SchemaValidator schemaValidator = new SchemaValidator(validationContext, "", jsonNode);

    String testData1 =
        "["
            + "{\n"
            + "  \"foo\": null\n"
            + "}"
            + "]";

    ObjectMapper mapper = new ObjectMapper();

    ValidationResults results = new ValidationResults();
    schemaValidator.validate(mapper.readTree(testData1), results);
    if (!results.isValid()) {
      System.out.println(results);
    }
  }
}

Expected behavior
Expected no schema validation errors when validating a non-required property that is null.

Additional context
Seems to happen only for array properties.

AbsOpenApiSchema.copyMap() doesn't honor map type

Describe the bug

AbsOpenApiSchema.copyMap() does not honor the source map type.

The properties of an object schema originally are stored in a LinkedHashMap to preserve the order of the properties. This is lost by copyMap().

It happens when I try to resolve a ref schema like this:

def resolved = schema.copy (api.context, true)

Similar looking $ref strings can collide

Describe the bug
A modular OpenAPI spec can include two $refs with the same relative path, but different targets. These should be treated as different refs, but openapi4j-parser sees them as the same.

To Reproduce
See: https://github.com/romacafe/openapi4j-refs.

Basically, this structure contains identical $ref strings that should refer to different content.

/
+- api.yaml
|  +- $ref testType.yaml#/TestType
|  \- $ref schema2/schema2.yaml#/Schema2
+- testType.yaml
|  \- TestType (definition 1)
\- schema2
   +- schema2.yaml
   |  \- $ref testType.yaml#/TestType
   \- testType.yaml
      \- TestType (definition 2)

Expected behavior
/testType.yaml#/TestType and /schema2/testType.yaml#/TestType should be recognized as different types, even when relative refs (TestType.yaml#/TestType) look the same.

Additional context
Yes this is somewhat contrived, but large APIs are more maintainable when modularized, and it would be good to know conflicts like this can't happen. Otherwise, we'd need to be careful that all $ref values are unique.

Body.from does not support List<Object>

Describe the bug
The Body.from adapter only supports Map<String, Object>, but it is quite valid to have an array not enclosed within a map. (bare values such as 'true' and '10' are also valid JSON).

To Reproduce

  1. Attempt to call Body.from(List xx)
  2. compilation error
  3. Expected behavior
    Expect to be able to build a response/request object from a List<Object>

    Additional context
    Have tried adding the List<Object> wrapper and it works as expected.

    Will submit a pull request shortly.

Chain custom validation

Describe the bug
Question (not a bug): Is it possible to chain custom validators to the original core validator?

In particular I have written a new "format" validator to trap 'date-time' and 'date' formats and record them (for later data conversion). I would like to then delegate the validation to the original 'FormatValidator' behaviour for validation against other well-known formats.

To Reproduce
Steps to reproduce the behavior:

  1. Create a 'format' validator as per https://github.com/openapi4j/openapi4j/tree/master/openapi-schema-validator
  2. Validate a body with invalid values with respect to the 'format' value.

Validation error on responses http status code ranges

Describe the bug
Http status code ranges (e.g. 5XX) in OpenAPI 3 Responses object do not validate successfully.

To Reproduce
Steps to reproduce the behavior:

  1. Add a status code range to a responses object in an existing OpenAPI spec i.e.
responses:
   "200":
      description: Success
   "5XX":
      description: Unexpected error
  1. Attempt to validate spec using OpenApi3Validator
  2. Validation error is displayed with message Invalid key '5XX' in map 'default|\d\d\d\'

Expected behavior
There should be no validation errors.

Additional context
Status code ranges are allowed in OpenAPI 3.

Add data along schema crumbs in ValidationResults

This would allow to get a net result of the data with the current schema path in ValidationResults object.

This includes a minor breaking change in ValidationItem:

  • current crumbs() method is renamed to schemaCrumbs()
  • a new dataCrumbs() method is added to get the path of data.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.