swaggest / php-json-schema

High definition PHP structures with JSON-schema based validation
MIT License
451 stars 51 forks source link

File resolution broken since merge of #69, issue #66 v0.12.7 #70

Closed williamdes closed 5 years ago

williamdes commented 5 years ago

https://github.com/swaggest/php-json-schema/releases/tag/v0.12.7 broke file resolve process

Test data

schemas
    - example_item.json
    - stats.json
- index.php

stats.json

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "urn:example:api:response-example",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "confirmed",
    "to_pay"
  ],
  "definitions": {
    "example_item": {
      "$ref": "example_item.json"
    }
  },
  "properties": {
    "confirmed": {
      "$ref": "example_item.json"
    },
    "to_pay": {
      "$ref": "example_item.json"
    }
  }
}

example_item.json

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "urn:example:api:example_item",
  "type": "object",
  "additionalProperties": false,
  "required": ["_type", "count"],
  "properties": {
    "_type": {
      "$id": "#/definitions/example_item/properties/confirmed/properties/_type",
      "type": "string",
      "enum": ["example_item"]
    },
    "count": {
      "$id": "#/definitions/example_item/properties/confirmed/properties/count",
      "type": "integer"
    }
  }
}

index.php

<?php

require(__DIR__ . '/vendor/autoload.php');
$file = __DIR__ . "/schemas/stats.json";
use Swaggest\JsonSchema\Schema;

var_dump("File exists: " . is_file($file));

try {
    $schema = Schema::import($file);
    $schema->in((object)[]);
} catch (Exception $e) {
            // Normal: Required property missing: confirmed, data: [] at #->$ref[/mnt/Dev/xxxyyyzzz/testbench/schemas/stats.json]
            // Fails: file_get_contents(example_item.json): failed to open stream: No such file or directory in /mnt/Dev/xxxyyyzzz/testbench/vendor/swaggest/json-schema/src/RemoteRef/BasicFetcher.php on line 11
            // Err: Object, boolean expected, null received at #->$ref:/mnt/Dev/xxxyyyzzz/testbench/schemas/stats.json->properties:definitions->additionalProperties:example_item->$ref:example_item.json at #->$ref:/mnt/Dev/xxxyyyzzz/testbench/schemas/stats.json->properties:definitions->additionalProperties:example_item
    echo PHP_EOL . "------------------" . PHP_EOL;
    print_r($e->getMessage());
    echo PHP_EOL . "------------------" . PHP_EOL;
}

See #66

Introduced by #69

williamdes commented 5 years ago

cc @vearutop

vearutop commented 5 years ago

This is interesting, though it seem to work according to JSON Schema spec.

$id sets base for following $ref, in this case you have $id: urn:example:api:response-example and then you refer to example_item.json which has to be resolved against urn:.... https://json-schema.org/latest/json-schema-core.html#rfc.section.8.3.2:

In all cases, dereferencing a "$ref" reference involves first resolving its value as a URI reference against the current base URI per RFC 3986 [RFC3986].

This does not make sense and falls under RFC 3986 requirements:

When presented with a URI that violates one or more scheme-specific restrictions, the scheme-specific resolution process should flag the reference as an error rather than ignore the unused parts; doing so reduces the number of equivalent URIs and helps detect abuses of the generic syntax, which might indicate that the URI has been constructed to mislead the user (Section 7.6).

Your options to fix the issue:

In case your schema identity does not allow any discovery (urn) you need to preload your schemas before validation, example.