Closed sanjjaymahalingam closed 9 months ago
Can we make the changes in gem to get error message with inner required missing fields as shown above?
Could you provide a smaller example schema to reproduce the issue?
can we add extra keys called custom_schema
, the same as schema
, and schema_pointer
in the response which we get after validate
?
custom_schema will have the responsibility of extracting only the node object and not the entire schema
cc: @shubham-n-khanna @sanjjaymahalingam
Hey @ahx, here is the JSON schema file we are using. Would it be of help:- schema.json
here is the JSON schema file we are using. Would it be of help:- schema.json
That schema is quite complex, but I see at least one condition where fulfillment_availability
would be required:
{
"$schema": "https://schemas.amazon.com/selling-partners/definitions/product-types/meta-schema/v1",
"$id": "https://schemas.amazon.com/selling-partners/definitions/product-types/schema/v1/BEAUTY",
...
"allOf": [
...
{
"if": {
"allOf": [
{
"not": {
"required": [
"parentage_level"
],
"properties": {
"parentage_level": {
"contains": {
"required": [
"value"
],
"properties": {
"value": {
"enum": [
"parent"
]
}
}
}
}
}
}
},
{
"not": {
"required": [
"skip_offer"
],
"properties": {
"skip_offer": {
"contains": {
"required": [
"value"
],
"properties": {
"value": {
"enum": [
true
]
}
}
}
}
}
}
}
]
},
"then": {
"required": [
"fulfillment_availability"
]
}
},
...
]
}
In order to debug this further, I would need a much simpler example schema and example data.
can we add extra keys called
custom_schema
, the same asschema
, andschema_pointer
in the response which we get aftervalidate
? custom_schema will have the responsibility of extracting only the node object and not the entire schema cc: @shubham-n-khanna @sanjjaymahalingam
I'm not sure what you mean by "only the node object"—can you provide an example?
An example schema and example data for debugging:-
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"$id": "https://schemas.amazon.com/selling-partners/definitions/product-types/schema/v1/BEAUTY",
"$comment": "Amazon product type definition for BEAUTY product type",
"$defs": {
"marketplace_id": {
"default": "ATVPDKIKX0DER",
"editable": false,
"hidden": true,
"examples": ["Amazon.com"],
"type": "string",
"anyOf": [
{ "type": "string" },
{
"type": "string",
"enum": ["ATVPDKIKX0DER"],
"enumNames": ["Amazon.com"]
}
]
},
"language_tag": {
"default": "en_US",
"editable": false,
"hidden": true,
"examples": ["English (United States)"],
"type": "string",
"anyOf": [
{ "type": "string" },
{
"type": "string",
"enum": ["en_US"],
"enumNames": ["English (United States)"]
}
]
}
},
"type": "object",
"required": [
"brand",
"fulfillment_availability"
],
"properties": {
"brand": {
"title": "Brand Name",
"description": "Max. 50 characters",
"examples": ["Sonny Brook Hams"],
"type": "array",
"minItems": 1,
"minUniqueItems": 1,
"maxUniqueItems": 1,
"selectors": ["marketplace_id", "language_tag"],
"items": {
"type": "object",
"required": ["language_tag", "marketplace_id", "value"],
"properties": {
"value": {
"title": "Brand Name",
"description": "Provide the brand name of the product",
"editable": false,
"hidden": false,
"examples": ["Sony"],
"type": "string",
"minLength": 1,
"maxLength": 100
},
"language_tag": { "$ref": "#/$defs/language_tag" },
"marketplace_id": { "$ref": "#/$defs/marketplace_id" }
},
"additionalProperties": false
}
},
"fulfillment_availability": {
"title": "Fulfillment Availability",
"description": "For those merchants using Amazon fulfillment services, please provide associated logistical information.",
"type": "array",
"minItems": 1,
"minUniqueItems": 1,
"maxUniqueItems": 1,
"selectors": ["fulfillment_channel_code"],
"items": {
"type": "object",
"required": ["fulfillment_channel_code"],
"properties": {
"fulfillment_channel_code": {
"title": "Fulfillment Channel Code",
"description": "For those merchants using Amazon fulfillment services, this designates which fulfillment network will be used. Specifying a value other than DEFAULT will cancel the Merchant-fulfilled offering.",
"editable": true,
"hidden": false,
"examples": ["AMAZON_NA"],
"type": "string",
"enum": ["AMAZON_NA", "DEFAULT"],
"enumNames": ["AMAZON_NA", "DEFAULT"]
},
"quantity": {
"title": "Quantity",
"description": "Enter the quantity of the item you are making available for sale. This is your current inventory commitment (as a whole number)",
"editable": true,
"hidden": false,
"examples": ["152"],
"type": "integer",
"minimum": 0
}
},
"additionalProperties": false
}
}
}
}
data:-
{
"brand": [
{
"value": "some value here",
"language_tag": "en_US",
"marketplace_id": "ATVPDKIKX0DER"
}
]
}
@davishmcclurg let me share one example for better understanding. when we validate the schema it gives a response in the format below
# => [{"data"=>10,
# "data_pointer"=>"/abc",
# "schema"=>{"type"=>"integer", "minimum"=>11},
# "schema_pointer"=>"/properties/abc",
# "root_schema"=>{"type"=>"object", "properties"=>{"abc"=>{"type"=>"integer", "minimum"=>11}}},
# "type"=>"minimum",
# "error"=>"number at `/abc` is less than: 11"}]
so can we add one more field called custom_schema
which will contain the schema of that field instead of the entire schema.
e.g
# => [{"data"=>10,
# "data_pointer"=>"/abc",
# "schema"=>{"type"=>"integer", "minimum"=>11},
# "schema_pointer"=>"/properties/abc",
# "root_schema"=>{"type"=>"object", "properties"=>{"abc"=>{"type"=>"integer", "minimum"=>11}}},
# "type"=>"minimum",
# "custom_schema"=> "{
# "title": "Fulfillment Availability",
# "description": "For those merchants using Amazon fulfillment services, please provide associated logistical information.",
# "type": "array",
# "minItems": 1,
# "minUniqueItems": 1,
# "maxUniqueItems": 1,
# "selectors": ["fulfillment_channel_code"],
# "items": {
# "type": "object",
# "required": ["fulfillment_channel_code"],
# "properties": {
# "fulfillment_channel_code": {
# "title": "Fulfillment Channel Code",
# "description": "For those merchants using Amazon fulfillment services, this designates which fulfillment network will be used. Specifying a value other than DEFAULT will cancel the Merchant-fulfilled offering.",
# "editable": true,
# "hidden": false,
# "examples": ["AMAZON_NA"],
# "type": "string",
# "enum": ["AMAZON_NA", "DEFAULT"],
# "enumNames": ["AMAZON_NA", "DEFAULT"]
# },
# "quantity": {
# "title": "Quantity",
# "description": "Enter the quantity of the item you are making available for sale. This is your current inventory commitment (as a whole number)",
# "editable": true,
# "hidden": false,
# "examples": ["152"],
# "type": "integer",
# "minimum": 0
# }
# },
# "additionalProperties": false
# }
# }
# }"
# "error"=>"number at `/abc` is less than: 11"}]
by doing this we can use the custom_schema field for our purpose.
An example schema and example data for debugging:-
@sanjjaymahalingam in that example, fulfillment_availability
is explicitly required. Here is the output I get:
irb(main):015> JSONSchemer.schema(schema).validate(instance).map { |r| r.except('root_schema', 'schema') }
=>
[{"data"=>{"brand"=>[{"value"=>"some value here", "language_tag"=>"en_US", "marketplace_id"=>"ATVPDKIKX0DER"}]},
"data_pointer"=>"",
"schema_pointer"=>"",
"type"=>"required",
"error"=>"object at root is missing required properties: fulfillment_availability",
"details"=>{"missing_keys"=>["fulfillment_availability"]}}]
That seems correct to me. What output are you expecting?
so can we add one more field called
custom_schema
which will contain the schema of that field instead of the entire schema.
@rohit-lingayat-sd would custom_schema
always return the top-level properties
schema for a certain property? In the output, schema
is already the current property schema ("schema"=>{"type"=>"integer", "minimum"=>11}
in your example). If you want access to intermediate schemas, I would use schema_pointer
to walk through your schema to whatever level you need.
{
"data": { "brand": [{ "value": "some value here", "language_tag": "en_US", "marketplace_id": "ATVPDKIKX0DER" }]},
"data_pointer": "/fulfillment_availability/0",
"schema_pointer": "",
"type": "required",
"error": "object at `/fulfillment_availability/0` is missing required properties: fulfillment_channel_code",
"details": { "missing_keys": [ "fulfillment_channel_code"]}
}
We were thinking the gem should provide a more precise response like this where it states that the fulfillment_channel_code
in the fulfillment_availability
parent object is missing even if the whole fulfillment_availability
object is not provided in the input. When a parent object is missing it should check all the required child fields in the parent object (in this case only fulfillment_channel_code
) and then provide an error as above.
When a parent object is missing it should check all the required child fields in the parent object (in this case only
fulfillment_channel_code
) and then provide an error as above.
If the parent is missing, aren't you able to assume any required child fields are missing as well? I don't think it makes sense to do speculative validation like that, since we can't know what the parent object would look like if it were provided. Child requirements could also be conditional on the value of the parent object.
While trying to validate a JSON payload against a particular JSON schema which is based on JSON draft 2019-09 the following errors are returned from the gem:-
In the response above the missing parent fields have been listed. For example as the fulfillment_availability parent object is missing from the JSON payload the gem gives the following error:-
According to the JSON schema file the schema for fulfilment_availabilty is as follows:-
As per the schema, only fulfillment_channel_code in the parent object fulfillment_availability is a required field. Hence as a suggestion if the parent object fulfillment_availability is missing the gem should give an error message as follows:-