gregsdennis / Manatee.Json

A fully object-oriented approach to JSON manipulation, validation, and serialization that focuses on modeling the JSON structure rather than mere string parsing and conversion.
MIT License
198 stars 32 forks source link

Get embedded schema from definitions of another schema #273

Closed bard83 closed 4 years ago

bard83 commented 4 years ago

Hi, I'm facing the current scenario, I have a schema file (global-schema-definition.json) that defines under definitions another schema, identified by the $id inner-schema-definition. Below its pseudo definition:

{
  "$id": "myurl/global-schema-definition.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
       "inner-schema-definition": {
            "$id": "inner-schema-definition",
            "$schema": "http://json-schema.org/draft-07/schema#",
             "type": "object",
             // definition of the schema
        }
   },
  "type": "object",
  "required": ["a", "b", "c"],
  "properties": {
      "a": {
         "$ref": "#/definitions/inner-schema-definition"
       },
       // followed by definition of b and c
  }
}

I have a second schema file (inner-schema-definition.json) that repeat the content of definitions/inner-schema-definition

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
     // definition of the schema 
}

In the application there are two kinds of validator one for global-schema-definition (ValidatorGD) and another one for inner-schema-definition (ValidatorID). I would like to drop the file inner-schema-definition.json in order to point directly to global-schema-definition.json#definitions/inner-schema-definition. Here how the `inner-schema-definition schema is read

var schema = JsonSchemaRegistry.Get($"file://{AppDomain.CurrentDomain.BaseDirectory}/Schemas/inner-schema-definition.json");

Here how I'd like to read it

var schema = JsonSchemaRegistry.Get($"file://{AppDomain.CurrentDomain.BaseDirectory}/Schemas/global-schema-definition.json#/definitions/inner-schema-definition");

The second case reads the entire content of global-schema-definition.json ignoring the #/definitions/inner-schema-definition part. Obviously inner-schema-definition objects are invalid when they are validated against schema.

What I'm trying to do is supported by JsonSchemaRegistry?

bard83 commented 4 years ago

Change inner-schema-definition.json as below, will save the content duplication.

{
    "type": "object",
    "allOf": [
    {
      "$ref": "global-schema-definition.json#/definitions/inner-schema-definition"
    }
  ]
}

So I can continue use the previous approach:

var schema = JsonSchemaRegistry.Get($"file://{AppDomain.CurrentDomain.BaseDirectory}/Schemas/inner-schema-definition.json");

My question is still in place.

gregsdennis commented 4 years ago

JsonSchemaRegistry will only read a file as a whole. It's not going to navigate into the file to find some sub-content. This isn't a feature I'm going to add.

If this is really the way you want to go with it, You have a couple options:

  1. You can read the whole schema, then use JsonSchema.ResolveSubschema() with the fragment as a JsonPointer.
  2. You can load the schema manually by reading the file data and parsing the data. Then you can use the fragment as a JsonPointer to find the part of the JsonValue that you want and deserialize that.

My suggestion is to go the route of your second comment where you store the subschema as a separate file and reference to it in the first. This is the typical "proper" approach.

bard83 commented 4 years ago

Thanks for your reply and for your suggestions. I'll proceed with my second comment. Also for me makes more sense and there is no reason for JsonSchemaRegistry to dig into the schema to retrieve part of it. I'll only invert the dependency. Currently inner-schema-definition.json depends from global-schema-definition.json. The other way around is more explicit, global-schema-definition.json depends from inner-schema-definition.json, because keeps concerns strictly separated and mostly it won't lead in to temptation to dig into the schemas.

{
"$id": "myurl/global-schema-definition.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["a", "b", "c"],
  "properties": {
      "a": {
         "$ref": "inner-schema-definition.json#/definitions/inner-schema-definition"
       },
       // followed by definition of b and c
  }
}
{
     "$id": "myurl/inner-schema-definition.json",
     "$schema": "http://json-schema.org/draft-07/schema#",
     "definitions": {
       "inner-schema-definition": {
            "$id": "inner-schema-definition",
            "$schema": "http://json-schema.org/draft-07/schema#",
             "type": "object",
             // definition of the schema
        }
    },
    "type": "object",
    "allOf": [
    {
      "$ref": "#/definitions/inner-schema-definition"
    }
  ]
}
var schema = JsonSchemaRegistry.Get($"file://{AppDomain.CurrentDomain.BaseDirectory}/Schemas/inner-schema-definition.json");

Thanks. Best Sante