0

I have JSON schema generated using JsonSchema.Net.Generation. My classes for schema are as below:

class PaymentInitiationSchema
{
    [Required]
    [JsonPropertyName("type")]
    public string Type { get; set; }

    [Required]
    [JsonPropertyName("actions")]
    public string[] Actions { get; set; }

    [Required]
    [JsonPropertyName("locations")]
    public string[] Locations { get; set; }

    [Required]
    [JsonPropertyName("instructedAmount")]
    public InstructedAmount InstructedAmount { get; set; }

    [Required]
    [JsonPropertyName("creditorName")]
    public string CreditorName { get; set; }

    [Required]
    [JsonPropertyName("creditorAccount")]
    public CreditorAccount CreditorAccount { get; set; }

    [Required]
    [JsonPropertyName("reemitanceInformationUnstructured")]
    public string ReemitanceInformationUnstructured { get; set; }
}

class InstructedAmount
{
    [Required]
    [JsonPropertyName("currency")]
    public string Currency { get; set; }

    [Required]
    [JsonPropertyName("amount")]
    public decimal Amount { get; set; }
}

class CreditorAccount
{
    [Required]
    [JsonPropertyName("iban")]
    public string Iban { get; set; }
}

and it's the generated schema:

{
   "type":"object",
   "properties":{
      "type":{
         "type":"string"
      },
      "actions":{
         "$ref":"#/$defs/array"
      },
      "locations":{
         "$ref":"#/$defs/array"
      },
      "instructedAmount":{
         "type":"object",
         "properties":{
            "currency":{
               "type":"string"
            },
            "amount":{
               "type":"number"
            }
         },
         "required":[
            "currency",
            "amount"
         ]
      },
      "creditorName":{
         "type":"string"
      },
      "creditorAccount":{
         "type":"object",
         "properties":{
            "iban":{
               "type":"string"
            }
         },
         "required":[
            "iban"
         ]
      },
      "reemitanceInformationUnstructured":{
         "type":"string"
      }
   },
   "required":[
      "type",
      "actions",
      "locations",
      "instructedAmount",
      "creditorName",
      "creditorAccount",
      "reemitanceInformationUnstructured"
   ],
   "$defs":{
      "array":{
         "type":"array",
         "items":{
            "type":"string"
         }
      }
   }
}

I created sample function to validate given JSON:

static bool IsValid(string requestedAuthorizationDetails, JsonSchema authorizationDetailsSchema)
{
    try
    {
        JsonDocument.Parse(requestedAuthorizationDetails);
    }
    catch
    {
        return false;
    }

    var result = authorizationDetailsSchema.Validate(requestedAuthorizationDetails, new ValidationOptions
    {
        OutputFormat = OutputFormat.Detailed
    });

    Console.WriteLine(result.Message + " at " + result.SchemaLocation.Source);

    return result.IsValid;
}

And it's always false for this call:

var schemaBuilder = new JsonSchemaBuilder();
var schema = schemaBuilder.FromType<PaymentInitiationSchema>().Build();

Console.WriteLine(IsValid(@"{
      ""type"": ""payment_initiation"",
      ""actions"": [
         ""initiate"",
         ""status"",
         ""cancel""
      ],
      ""locations"": [
         ""https://example.com/payments""
      ],
      ""instructedAmount"": {
         ""currency"": ""EUR"",
         ""amount"": 123.50
      },
      ""creditorName"": ""Merchant A"",
      ""creditorAccount"": {
         ""iban"": ""DE02100100109307118603""
      },
      ""remittanceInformationUnstructured"": ""Ref Number Merchant""
   }", schema));

And the error is also always the same:

Value is "string" but should be "object" at #/type

Really don't understand why. I thought that maybe there is conflict between type at top of the JSON scheme and the type as required parameter. But even if I removed type from parameters the same error stills occurs.

What's wrong with it?

Szyszka947
  • 473
  • 2
  • 5
  • 21

1 Answers1

1

I'm not sure what version of the libs you're using, but have you checked over at https://json-everything.net?

Inputting your generated schema and the instance you wrote, it says that two properties are the problems (I've edited the output down to just the errors for ease of viewing):

{
  "valid": false,
  "evaluationPath": "",
  "schemaLocation": "https://json-everything.net/43e8b7754c",
  "instanceLocation": "",
  "errors": {
    "required": "Required properties [\"reemitanceInformationUnstructured\"] were not present"
  },
  "details": [
    {
      "valid": false,
      "evaluationPath": "/properties/creditorAccount",
      "schemaLocation": "https://json-everything.net/43e8b7754c#/properties/creditorAccount",
      "instanceLocation": "/creditorAccount",
      "errors": {
        "required": "Required properties [\"iban\"] were not present"
      }
    }
  ]
}

It looks like you have two typos. Changing remittanceInformationUnstructured to reemitanceInformationUnstructured and ban to iban allows the data to validate.

gregsdennis
  • 7,218
  • 3
  • 38
  • 71
  • Instead of passing the string to the `Validate` function, I started passing this string parsed to JsonDocument and everything works now. Any ideas why? – Szyszka947 Feb 23 '23 at 18:44
  • 1
    The `Validate()` method actually takes a `JsonNode`, and there's an implicit conversion from `string` to `JsonNode`. So you were validating a string. You can read the docs at https://json-everything.net/json-schema#evaluating-instances. I'll try to add a note about the gotcha about strings. It's tripped up several people. – gregsdennis Feb 23 '23 at 19:35
  • 1
    Another note: Those docs are for the 4.0 beta version. For `Evaluate()` just use `Validate()` if you're using the 3.x version. – gregsdennis Feb 23 '23 at 19:37