thephpleague / json-guard

Validation of json-schema.org compliant schemas.
http://json-guard.thephpleague.com/
MIT License
175 stars 26 forks source link

InvalidSchemaException on valid schema #125

Closed lukeocodes closed 7 years ago

lukeocodes commented 7 years ago

We have a larger framework for consuming APIs, so by the time we attempt to validate we have the schema body. In this particular example the schema is actually behind oauth as well, which is helpful.

The schema is stored in a temporary file as it appears Deferencer requires a schema Uri.

namespace Bundle\Validator;

use League\JsonGuard\Validator;
use League\JsonReference\Dereferencer;

class JsonValidator implements ValidatorInterface
{
    /**
     * @param string $schemaBody
     * @param array $requestBody
     */
    public function validateRequestBody($schemaBody, array $requestBody)
    {
        $tempFileName = tempnam("/tmp", "schema_");
        $handle = fopen($tempFileName, "w");
        fwrite($handle, $schemaBody);
        fclose($handle);

        $dereferencer = new Dereferencer();
        $schemaBody = $dereferencer->dereference('file://' . realpath($tempFileName));

        $validator = new Validator(json_decode(json_encode($requestBody)), $schemaBody);

        if ($validator->fails()) {
            $errors = $validator->errors();
        }
    }
}

When it runs I get

InvalidSchemaException

With the message

Value has type "boolean" but must be one of: "array"

The Schema: https://pastebin.com/6njYBf70

The data payload:

{
   "network":{
      "network_id":9038
   },
   "branch":{
      "branch_id":29376,
      "channel":1
   },
   "property":{
      "agent_ref":"HSS1013",
      "published":true,
      "property_type":4,
      "status":1,
      "create_date":"06-10-2017 09:36:31",
      "update_date":"06-10-2017 09:36:31",
      "address":{
         "house_name_number":"8",
         "address_2":"Ward Passage",
         "address_4":"Suffolk",
         "town":"Lewishaven",
         "postcode_1":"Q61",
         "postcode_2":"6IK",
         "display_address":"Ward Passage, Lewishaven, Q61",
         "latitude":-14.544987,
         "longitude":-67.221535
      },
      "price_information":{
         "price":397611,
         "price_qualifier":0,
         "tenure_type":5,
         "rent_frequency":null
      },
      "details":{
         "summary":"The question is, what?' The great question is, Who in the flurry of the wood--(she considered him to you, Though they were nowhere to be otherwise than what you like,' said the Dormouse; 'VERY ill.'.",
         "description":"I would talk on such a curious feeling!' said Alice; 'that's not at all know whether it was very glad to do so. 'Shall we try another figure of the Lobster Quadrille?' the Gryphon in an impatient.",
         "features":[

         ],
         "bedrooms":9,
         "bathrooms":1,
         "reception_rooms":1,
         "parking":[
            16
         ],
         "heating":[
            9
         ],
         "furnished_type":null,
         "pets_allowed":false,
         "smokers_considered":false,
         "housing_benefit_considered":false,
         "rooms":[

         ]
      },
      "media":[

      ]
   }
}

Validating it using the justinrainbow/json-schema it validates fine, but json-guard works with other much more complex schema's that json-schema struggles with, especially with remote refs.

It also validates online using jsonschemavalidator.net against the above schema and payload.

Any ideas?

Update: I get the same exception without Referencer.

matt-allan commented 7 years ago

Hello,

You have "required": true in multiple parts of your schema. The required keyword requires an array specifying what properties are required; you can't nest it under individual properties.

If you get an InvalidSchemaException you can check your schema against the draft-4 meta schema. https://github.com/yuloh/json-guard-cli makes that a little easier. The exception also has a pointer to the part of the schema that caused it, so you can catch it to get more info:

try {
   $errors = $validator->errors();
} catch (League\JsonGuard\Exception\InvalidSchemaException $e) {
    var_dump($e->getPointer(), $e->getKeyword());
}

Validating it using the justinrainbow/json-schema it validates fine, but json-guard works with other much more complex schema's that json-schema struggles with, especially with remote refs.

It also validates online using jsonschemavalidator.net against the above schema and payload.

Neither of those validators seem to check the schema itself, they just ignore invalid parts of the schema. https://jsonschemalint.com will actually check the schema itself.

The id keywords in the schema are also invalid for Draft-4. They should be URIs. Make sure you read the links below because the id will change how dereferencing works.

The schema is stored in a temporary file as it appears Deferencer requires a schema Uri.

You can dereference an object, but it needs to be json_decoded as an object, not an array and you can't use relative references without IDs. Otherwise it won't know where the URI is relative to and it won't be able to resolve the reference. For example, if your schema contains {"$ref": "./other-schema.json" it can't resolve that without knowing where you initially loaded the schema from.

Hopefully that helps. Let me know if you have any further questions.

lukeocodes commented 7 years ago

Great, thanks. I think this is a json-schema draft's version error. They work to draft-03 I believe. It's a vendor schema, so my hands are slightly tied.

:+1: thanks for your help.