skip to Main Content

Newtonsoft.Json.Schema is not validating JSON input correctly against a JSON schema

In below example schema validation is returning true for the below payload JSON, even though:

  • for "mCRO" nullable is set to false
  • iNumber" has varchar(10)

Why are these errors not getting caught?

We are using Newtonsoft.Json.Schema for validation.

JSON Schema :

{
    "openapi": "3.0.2",
    "info": {
        "title": "Demo API",
        "version": "1.1.1",
        "description": "<b>Demo version"
    },
    "tags": [
        {
            "name": "Records",
            "description": "Registration"
        }
    ],
    "paths": {
        "/records/AddUpdateRecord": {
            "post": {
                "tags": [
                    "Records"
                ],
                "description": "Add or Update a Object",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/addUpdateRecords"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK - Indicates that the request has succeeded.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/httpResponse200"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/httpResponse400"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Unauthorized "
                    },
                    "403": {
                        "description": "Forbidden - Unauthorized request."
                    },
                    "429": {
                        "description": "Too Many Requests "
                    },
                    "500": {
                        "description": "Internal Server Error "
                    }
                }
            }
        },
        "/records/AddUpdateC": {
            "post": {
                "tags": [
                    "Records"
                ],
                "description": "Add or Update existing 1 to N Coverages.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/addUpdateC"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK - Indicates that the request has succeeded.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/httpResponse200"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad Request ",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/httpResponseC400"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Unauthorized ."
                    },
                    "403": {
                        "description": "Forbidden."
                    },
                    "429": {
                        "description": "Too Many Requests "
                    },
                    "500": {
                        "description": "Internal Server Error "
                    }
                }
            }
        },
        "/records/UpdateRO": {
            "put": {
                "tags": [
                    "Records"
                ],
                "description": "Update an existing RO.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/updateRO"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK - Indicates that the request has succeeded.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/httpResponse200"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad Request ",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/httpResponse400"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Unauthorized"
                    },
                    "403": {
                        "description": "Forbidden ."
                    },
                    "429": {
                        "description": "Too Many Requests ."
                    },
                    "500": {
                        "description": "Internal Server Error "
                    }
                }
            }
        },
        "/records/RemoveRO": {
            "post": {
                "tags": [
                    "Records"
                ],
                "description": "Remove an existing RO",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/removeRO"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK - Indicates that the request has succeeded.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/httpResponse200"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad Request.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/httpResponse400"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Unauthorized."
                    },
                    "403": {
                        "description": "Forbidden"
                    },
                    "429": {
                        "description": "Too Many Requests ."
                    },
                    "500": {
                        "description": "Internal Server Error"
                    }
                }
            }
        },
        "/records/MoveP": {
            "post": {
                "tags": [
                    "Records"
                ],
                "description": "Move",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/moveP"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK - Indicates that the request has succeeded.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/httpResponse200"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Bad Request.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/httpResponse400"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Unauthorized ."
                    },
                    "403": {
                        "description": "Forbidden "
                    },
                    "429": {
                        "description": "Too Many Requests ."
                    },
                    "500": {
                        "description": "Internal Server Error."
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "httpResponse200": {
                "type": "object",
                "properties": {
                    "results": {
                        "nullable": true,
                        "example": null
                    },
                    "requestGuid": {
                        "type": "string",
                        "example": "GUI"
                    },
                    "errors": {
                        "nullable": true,
                        "example": null
                    },
                    "httpStatusCode": {
                        "type": "integer",
                        "nullable": false,
                        "example": 200
                    }
                }
            },
            "addUpdateC": {
                "type": "object",
                "properties": {
                    "iCR": {
                        "type": "array",
                        "description": "1 to N",
                        "items": {
                            "type": "object",
                            "properties": {
                                "requestGuid": {
                                    "type": "string",
                                    "example": "GUI",
                                    "nullable": false
                                },
                                "iNumber": {
                                    "type": "string",
                                    "format": "varchar(10)",
                                    "nullable": false
                                },
                                "eTypeRequest": {
                                    "type": "array",
                                    "description": "1 to N",
                                    "items": {
                                        "type": "object",
                                      "properties": {
                                        "requestGuid": {
                                          "type": "string",
                                          "example": "16-byte binary value",
                                          "nullable": false
                                        },
                                        "eTypeECode": {
                                          "type": "string",
                                          "format": "varchar(3)",
                                          "nullable": false,
                                          "description": "List"
                                        }
                                      }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "moveP": {
                "type": "object",
              "properties": {
                "iMPR": {
                  "type": "object",
                  "properties": {
                    "requestGuid": {
                      "type": "string",
                      "example": "GUID",
                      "nullable": false
                    },
                    "iNumber": {
                      "type": "string",
                      "format": "varchar(10)",
                      "nullable": false
                    }
                  }
                }
              }
            },
            "removeRO": {
                "type": "object",
              "properties": {
                "iRROR": {
                  "type": "object",
                  "properties": {
                    "requestGuid": {
                      "type": "string",
                      "example": "GUID",
                      "nullable": false
                    },
                    "iNumber": {
                      "type": "string",
                      "format": "varchar(10)",
                      "nullable": false
                    },
                    "mCRO": {
                      "type": "number",
                      "format": "smallint",
                      "nullable": false,
                      "description": "List"
                    }
                  }
                }
              }
            },
            "addUpdateRecords": {
                "type": "object",
              "properties": {
                "iROR": {
                  "type": "object",
                  "properties": {
                    "requestGuid": {
                      "type": "string",
                      "example": "GUID",
                      "nullable": false
                    },
                    "iNumber": {
                      "type": "string",
                      "format": "varchar(10)",
                      "nullable": false
                    },
                    "mCRO": {
                      "type": "number",
                      "format": "smallint",
                      "nullable": false,
                      "description": "List"
                    }
                  }
                },
                "iCR": {
                  "type": "array",
                  "description": "1 to N",
                  "items": {
                    "type": "object",
                    "properties": {
                      "requestGuid": {
                        "type": "string",
                        "example": "16-byte binary value",
                        "nullable": false
                      },
                      "iNumber": {
                        "type": "string",
                        "format": "varchar(10)",
                        "nullable": false
                      },
                      "eTypeRequest": {
                        "type": "array",
                        "description": "1 to N",
                        "items": {
                          "type": "object",
                          "properties": {
                            "requestGuid": {
                              "type": "string",
                              "example": "16-byte binary value",
                              "nullable": false
                            },
                            "eTypeECode": {
                              "type": "string",
                              "format": "varchar(3)",
                              "nullable": false,
                              "description": "List"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            },
            "updateRO": {
                "type": "object",
              "properties": {
                "iROR": {
                  "type": "object",
                  "properties": {
                    "requestGuid": {
                      "type": "string",
                      "example": "GUID",
                      "nullable": false
                    },
                    "iNumber": {
                      "type": "string",
                      "format": "varchar(10)",
                      "nullable": false
                    },
                    "mCRO": {
                      "type": "number",
                      "format": "smallint",
                      "nullable": false,
                      "description": "List"
                    }
                  }
                }
              }
            },
            "httpResponse400": {
                "type": "object",
                "properties": {
                    "results": {
                        "nullable": true,
                        "example": null
                    },
                    "requestGuid": {
                        "type": "string",
                        "example": "GUI"
                    },
                    "errors": {
                        "type": "array",
                        "items": {
                            "type": "object",
                          "properties": {
                            "cTypeCode": {
                              "nullable": true,
                              "example": null
                            },
                            "cFormula": {
                              "nullable": true,
                              "example": null
                            },
                            "errorDescription": {
                              "type": "string"
                            }
                          }
                        }
                    },
                    "httpStatusCode": {
                        "type": "integer",
                        "nullable": false,
                        "example": 400
                    }
                }
            },
            "httpResponseC400": {
                "type": "object",
                "properties": {
                    "results": {
                        "nullable": true,
                        "example": null
                    },
                    "requestGuid": {
                        "type": "string",
                        "example": "GUI "
                    },
                    "errors": {
                        "type": "array",
                        "items": {
                            "type": "object",
                          "properties": {
                            "cTypeCode": {
                              "nullable": true,
                              "example": null
                            },
                            "cFormula": {
                              "nullable": true,
                              "example": null
                            },
                            "errorDescription": {
                              "type": "string"
                            }
                          }
                        }
                    },
                    "httpStatusCode": {
                        "type": "integer",
                        "nullable": false,
                        "example": 400
                    }
                }
            }
        }
    }
}

Payload JSON:

{
  "iRROR": {
    "requestGuid": "GUID",
    "iNumber": "12345678910111213", 
    "mCRO": null
  }
}

C# Code:


    using (StreamReader file = File.OpenText(@"C:\Sample\OpenAPISpecification.json"))
    using (JsonTextReader reader = new JsonTextReader(file))
    {
    JSchema schema = JSchema.Load(reader);
    JObject json = JObject.Parse(File.ReadAllText(@"C:\Sample\iRROR.json"));
    
        //validate json
                IList<ValidationError> errors;
                bool valid = json.IsValid(schema, out errors);
    
    
                new ValidateResponse
                {
                    Valid = valid,
                    Errors = errors
                };
    
    
    
            }

Why are these errors not getting caught?

We are using Newtonsoft.Json.Schema for validation.

2

Answers


  1. To echo and expand on Daniel’s comment, OpenAPI contains schemas, but it is not itself a schema. (Technically, the schemas that OpenAPI 3.0 and earlier use are a modified JSON Schema Draft 4. Version 3.1 uses JSON Schema DRaft 2020-12 directly.)

    You’ll need an OpenAPI tool, like OpenAPI.Net.

    Login or Signup to reply.
  2. To further expand, format: varchar(10) is not a format recognized by OpenAPI for validation. You can find their supported formats in the registry they maintain https://spec.openapis.org/registry/format/

    type: string is matching your data.

    JSON Schema doesn’t use the format keyword for validation unless the implementation you are using has explicitly implemented it. By default, it’s not required to be supported by the JSON Schema specification

    Be aware, nullable is NOT a JSON Schema keyword, and thus not recognized during validation. This keyword is only defined by OpenAPI and enforced by the OpenAPI 3.0.x metaschema.

    Ultimately, there are a lot of nuances with using OAS 3.0.x and a JSON Schema validator. It’s recommended to use the latest OAS 3.1.x version which aligns closer to the actual JSON Schema specification.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search