Click here to Skip to main content
14,774,521 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Validate a Json using the Path Response Schema in an Open API schema where the schema has a $ref (Potentially recursively)
I'm trying to accomplish something along the lines of:
//HttpClient call to the /pet/{petId} endpoint with Get verb here
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
SomeBuiltInSchemaParser.Load(schema.json);
var isValid = SomeBuiltInSchemaParser.IsValid(@"/pet/{petId}", "GET", content);

The long of it
I want to test (programmatically in C#) that an endpoint implementing a path returns a json that matches the schema defined in the responses section of the json for that path.
For example, given (heavily redacted, only essential):
{
  "swagger": "2.0",
  "info": {
    "title": "Swagger Petstore",
    "termsOfService": "http://swagger.io/terms/",
  },
  "host": "petstore.swagger.io",
  "basePath": "/v2",
  "schemes": [
    "https",
    "http"
  ],
  "paths": {
    "/pet/{petId}": {
      "get": {
        "tags": [
          "pet"
        ],
        "summary": "Find pet by ID",
        "description": "Returns a single pet",
        "operationId": "getPetById",
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "petId",
            "in": "path",
            "description": "ID of pet to return",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "200": {
            "description": "successful operation",
            "schema": {
              "$ref": "#/definitions/Pet"
            }
          },
          "400": {
            "description": "Invalid ID supplied"
          },
          "404": {
            "description": "Pet not found"
          }
        },
        "security": [
          {
            "api_key": []
          }
        ]
      },
    },
  },
  "definitions": {
    "Pet": {
      "type": "object",
      "required": [
        "name",
        "photoUrls"
      ],
      "properties": {
        "id": {
          "type": "integer",
          "format": "int64"
        },
        "category": {
          "$ref": "#/definitions/Category"
        },
        "name": {
          "type": "string",
          "example": "doggie"
        },
        "photoUrls": {
          "type": "array",
          "xml": {
            "name": "photoUrl",
            "wrapped": true
          },
          "items": {
            "type": "string"
          }
        },
        "tags": {
          "type": "array",
          "xml": {
            "name": "tag",
            "wrapped": true
          },
          "items": {
            "$ref": "#/definitions/Tag"
          }
        },
        "status": {
          "type": "string",
          "description": "pet status in the store",
          "enum": [
            "available",
            "pending",
            "sold"
          ]
        }
      },
    },
    "ApiResponse": {
      "type": "object",
      "properties": {
        "code": {
          "type": "integer",
          "format": "int32"
        },
        "type": {
          "type": "string"
        },
        "message": {
          "type": "string"
        }
      }
    }
  },
  "externalDocs": {
    "description": "Find out more about Swagger",
    "url": "http://swagger.io"
  }
}


I have an HttpClient that calls [GET] /pet/{petId} and want to test the json content returned with the 200 status code that it satisfies the schema. Navigating to this path's response schema shows:
"$ref": "#/definitions/Pet"

Instead of being inline, it is a $ref. And could potentially be recursively ref, meaning navigating to #/definitions/Pet, its properties could also be $ref.

Is there a way to implement my above pseudocode with built in .Net or other robust 3rd party such as NewtonSoft? Or do I have to load the json schema and traverse all the $refs with custom code and put them together in the end for each path? I don't mind, but I have a feeling either .Net or Newtonsoft or something else have built-in (well-tested and already optimized) ways of doing this, just couldn't find it.
(Would greatly appreciate if someone already knows for this grinch might steal my Christmas :-))

What I have tried:

The following NewtonSoft library implementation works

// load schema
                JSchema schema = JSchema.Parse(jsonSchema);
                JToken data = JToken.Parse(content);

                // validate json
                IList<ValidationError> errors;
                bool valid = data.IsValid(schema, out errors);

But jsonSchema in this instance is the already put together schema such as below
{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "type": {
      "enum": [
        "string",
        "number",
        "boolean",
        "date",
        "address",
        "country",
        "email",
        "jason",
        "url",
        "image",
        "signature",
        "barcode",
        "combined"
      ]
    },
    "name": {
      "type": "string"
    },
    "static": {
      "type": "boolean"
    },
    "default": {
      "type": "string"
    },
    "title": {
      "type": "string"
    },
    "description": {
      "type": "string"
    },
    "metadata": {
      "type": "string"
    },
    "required": {
      "type": "boolean"
    },
    "optionList": {
      "type": "string"
    },
    "combinedFieldNames": {
      "type": "string"
    },
    "combinedFieldType": {
      "type": "string"
    },
    "combinedFieldSeparator": {
      "type": "string"
    },
  }
}


content
{
    "name": "new_field",
	"type": "string",
    "required": false,
}
Posted

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900