RicoSuter / NJsonSchema

JSON Schema reader, generator and validator for .NET
http://NJsonSchema.org
MIT License
1.39k stars 534 forks source link

How to validate subschema (like a schema in openapi)? #1117

Open AtosNicoS opened 4 years ago

AtosNicoS commented 4 years ago

Hi! I've written an OpenApi Spec for my Rest API. I want to validate the payload inside the server and the client test suit. The idea was to validate against the existing schemas inside the openapi spec.

But how do I reference a subschema? In My example I would use openapi.json/components/schemas/Test, but the referenced TestId is inside the same file. So I need to read the whole file to parse the schema provided as json path. How can I do this? If this is not possible with this library, does anyone know an alternative (preferred in c#).

[...]
"components": {
    "schemas": {
        "Test": {
            "description": "Test Object",
            "type": "object",
            "additionalProperties": false,
            "properties": {
                "firmwareVersion": {
                    "type": "string",
                    "description": "Version of the Firmware",
                    "example": "1.1.4"
                },
                "id": {
                    "$ref": "#/components/schemas/TestId"
                }
            }
        },
        "TestId": {
            "type": "string",
            "format": "uuid",
            "description": "TestId"
        }
    }
}
RicoSuter commented 4 years ago

After loading the document with eg OpenApiDocument.FromFileAsync() you can follow these references, something like:

document.Components.Schemas.First().Properties["id"].Reference
RicoSuter commented 4 years ago

Ah sorry, we are in the NJsonSchema repo :-) - you need to use the NSwag.Core package (which uses NJsonSchema under the hood) to parse OpenAPI specs. NJsonSchema itself can only be used to read JSON Schemas

AtosNicoS commented 4 years ago

Do you have an example on how to do that?

RicoSuter commented 4 years ago

Currently you can only validate JSON Schema out of the box. You could read an OpenAPI document traverse/retrieve a schema from it and then validate data with it. However the validator uses JSON Schema rules and not OpenAPI or Swagger rules (they are not the same).

AtosNicoS commented 4 years ago

But how would I extract the schema, so that all references are resolved?

If the validation of json schema and openapi is not the same, how can I validate my requests? I just want to add some validation on the server side, and on the client unit test side. I thought openapi would make things easier, but as far as I understand your comment, that tooling is not available yet (not from your nor from others.) Or did I miss anyhting here? Any help appreciated.

RicoSuter commented 4 years ago

if you load an OpenAPI document with the NSwag.Core then all references are resolved (but not inlined!)

The NJsonSchema JSON Schema validator based on the JsonSchema instance can handle these references.

AtosNicoS commented 4 years ago

But there is no option to validate it against the openapi rules, correct?

RicoSuter commented 4 years ago

But there is no option to validate it against the openapi rules, correct?

Yes, the OpenAPI specific properties (e.g. "nullable") are currently not validated.

We'd need to add these things to the https://github.com/RicoSuter/NJsonSchema/blob/master/src/NJsonSchema/Validation/JsonSchemaValidator.cs

e.g. add another parameter "schemaType" (default: JsonSchema) and then validate according to that.

AtosNicoS commented 4 years ago

Imagine this schema:

{
  "components": {
    "schemas": {
      "Pet": {
        "allOf": [
          {
            "$ref": "#/components/schemas/NewPet"
          },
          {
            "type": "object",
            "required": [
              "id"
            ],
            "properties": {
              "id": {
                "type": "integer",
                "format": "int64"
              }
            }
          }
        ]
      },
      "NewPet": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "tag": {
            "type": "string"
          }
        }
      }
    }
  }
}

And this data:

{
"name": "TestPet",
"tag": "cat",
"id": 32
}

And this invalid data

{
"nickname": "TestPet2",
"tag": "cat",
"id": 64
}

Except there are some openapi specific properties (like nullable), how would I validate this json with the provided schema? I'd need to validate against the schema path components/schemas/Pet.

corina10 commented 4 years ago

Hi, Not sure I got this correctly, Is it possible to use NSwag.Core to validate a Json object? NJsonSchema helped me validate the object but it would be more convenient for me to have the data model written in OpenAPI. Thank you!

royarin commented 4 years ago

if you load an OpenAPI document with the NSwag.Core then all references are resolved (but not inlined!)

The NJsonSchema JSON Schema validator based on the JsonSchema instance can handle these references.

If I read a schema from the openapi doc as schema=document.Result.Components.Schemas["schema1"] and then try to do a schemaData=schema.ToJson(), it fails if there is a referenced schema.

Error: System.InvalidOperationException: 'Could not find the JSON path of a referenced schema: Manually referenced schemas must be added to the 'Definitions' of a parent schema.'

I believe that then loading the openapi document using NSqag.Core does not resolve the references.

royarin commented 4 years ago

Found a way out. Apparently, it is not required to use ToJson(). The idea is to use var document = OpenApiDocument.FromJsonAsync(spec); var schema = document.Result.Components.Schemas["schema1"]; var test=sch.Validate(jobject);

Test is a collection of validation errors.

RicoSuter commented 4 years ago

Yep, but keep in mind that Validate() uses JSON Schema semantics and not OpenAPI semantics which might lead to slightly different results than you expect... Ideally there would be an overload of Validate() with a JsonSchemaType parameter.