karenetheridge / JSON-Schema-Modern

Validate data against a schema using a JSON Schema
https://metacpan.org/release/JSON-Schema-Modern/
Other
11 stars 1 forks source link

error parsing schema file with a minimum value for a number #86

Open lschierer opened 1 day ago

lschierer commented 1 day ago

given a schema file that has a component that sets a minimum value for something of type number, OpenAPI::Modern will refuse to load it saying "got ambiguous type, not number" on the minimum, then "not all properties are valid" on the object containing it. openapi.yaml.txt

I reduced my actual API file down enough to show the error fairly clearly without lots of extraneous stuff in it. This API file validates fine with both the SwaggerUI viewer and the ibm-openapi-validator (though it does show some warnings with the latter, it shows no errors).

lschierer commented 1 day ago

The thing is that I may have other similar false parsing bugs, but as this object is at the root of the tree of components, it is really difficult to figure out from the limited information in the error if the rest of the tree is failing because this did, or for other reasons as well. I can provide the entire yaml file if you'd like, but I figured a more minimal reproduction might be best to start with.

lschierer commented 1 day ago

I tried reading the spec in several different ways, ultimately settling on a variation of some example code you provided,

my $OpenAPISchemaCache;
sub get_openapi ($openapi_filename) {
    my $newTemp = 0;
    if(not defined($OpenAPISchemaCache)) {
      $OpenAPISchemaCache = File::Temp->new();
      $newTemp = true;
    }
    my $serialized_file = Path::Tiny::path($OpenAPISchemaCache);
    my $openapi_file = Path::Tiny::path($openapi_filename);
    my $openapi;
    if ($newTemp or $serialized_file->stat->mtime < $openapi_file->stat->mtime) {
      $openapi = OpenAPI::Modern->new(
        openapi_uri => '/',
        openapi_schema => Load($openapi_file->slurp_raw), # your openapi document
      );
      my $frozen = Sereal::Encoder->new({ freeze_callbacks => 1 })->encode($openapi);
      $serialized_file->spew_raw($frozen);
    }
    else {
      my $frozen = $serialized_file->slurp_raw;
      $openapi = Sereal::Decoder->new->decode($frozen);
    }

    return $openapi;
  }
karenetheridge commented 1 day ago

My next questions will be what perl version you are using, and the module version of whatever is turning the yaml file into a hashref, because that's what's mangling the number(s) in your schema.

lschierer commented 1 day ago

perl 5, version 40 on OSX.

the file doing the reading is here (note the branch in that link, the main branch of that repository doesn't have it).

the path to the file is constructed at line 75 and the function to read in the file is immediately on the next line. I'm not yet doing anything with the result, I currently still have the code in place using the document_filename parameter instead, but while that doesn't produce any errors, it also results in a program that apparently has an empty configuration object.

I'm running this locally with the command

dzil run script/EvonyWeb.pl daemon -m development
lschierer commented 1 day ago
$ cpan -l | grep -i openapi
Use of uninitialized value $ExtUtils::MakeMaker::_version::version in concatenation (.) or string at (eval 2230) line 7, <FILE> line 142.
OpenAPI::Modern 0.072
JSON::Validator::Schema::OpenAPIv2  undef
JSON::Validator::Schema::OpenAPIv3  undef
JSON::Schema::Modern::Document::OpenAPI 0.072
JSON::Schema::Modern::Vocabulary::OpenAPI   0.072
Mojolicious::Plugin::OpenAPI    5.09
Mojolicious::Plugin::OpenAPI::Cors  undef
Mojolicious::Plugin::OpenAPI::Security  undef
Mojolicious::Plugin::OpenAPI::SpecRenderer  undef
Mojolicious::Plugin::OpenAPI::Parameters    undef
Mojolicious::Plugin::OpenAPI::Modern    0.012
$

as you can see I've tried a few different modules in my quest to first understand and second get something working. I'm fairly sure that most of these are not being loaded though:

lschiere@80a997121f31:~/src/schierer/Game-EvonyTKR$ dzil listdeps | grep -i openapi
Smartmatch is deprecated at (eval 1872) line 8, <GEN23> line 32.
Smartmatch is deprecated at (eval 1872) line 15, <GEN23> line 32.
Smartmatch is deprecated at (eval 1873) line 8, <GEN23> line 32.
Smartmatch is deprecated at (eval 1873) line 15, <GEN23> line 32.
Smartmatch is deprecated at (eval 1874) line 8, <GEN23> line 32.
Smartmatch is deprecated at (eval 1874) line 15, <GEN23> line 32.
Smartmatch is deprecated at (eval 1875) line 11, <GEN23> line 32.
Smartmatch is deprecated at (eval 1875) line 21, <GEN23> line 32.
JSON::Schema::Modern::Document::OpenAPI
Mojolicious::Plugin::OpenAPI::Modern
OpenAPI::Modern
lschierer commented 1 day ago

the hashref would be coming from line 115. that Load function is from use YAML::XS qw{ LoadFile Load };

lschierer commented 1 day ago

I added a script file which has just the loading stuff extracted out from the rest of the Web.pm file

lschierer commented 1 day ago

I've also tried LoadFile($openapi_file) instead of the current Load($openapi_file->slurp_raw) that is there now. Both functions LoadFile and Load come from YAML::XS as I said. both versions of the loader do the same thing.

lschierer commented 1 day ago

I changed the loading to

my $loadedFile = LoadFile($openapi_file);
      say Data::Printer::p($loadedFile);

      $openapi = OpenAPI::Modern->new(
        openapi_uri => '/',
        openapi_schema => $loadedFile, # your openapi document
      );

and the Data::Printer output looks like it imported a number to me.

karenetheridge commented 1 day ago

Ah, you're using YAML::XS. So you're bumping into a parsing problem that it has there, see

https://github.com/ingydotnet/yaml-libyaml-pm/pull/110
https://github.com/ingydotnet/yaml-libyaml-pm/pull/111
https://github.com/ingydotnet/yaml-libyaml-pm/pull/112

The workaround, until this is fixed, is to use YAML::PP: my $schema = YAML::PP->new(boolean => 'JSON::PP')->load_file($filename);

You can see the effect of this with:

$; perl -MJSON::Schema::Modern::Utilities=get_type,is_type -MDevel::Peek -MYAML::XS=Load -wle'my $data = Load("---\nfoo: 1"); Dump($data->{foo}); print "type: ", get_type($data->{foo}); print "integer? ", 0+is_type($data->{foo}, "integer");'
SV = PVIV(0x123019238) at 0x12180b098
  REFCNT = 1
  FLAGS = (IOK,POK,pIOK,pPOK)
  IV = 1
  PV = 0x6000015591d0 "1"\0
  CUR = 1
  LEN = 16
type: ambiguous type
integer? 0
lschierer commented 22 hours ago

Changing to YAML::PP did indeed get me past any issue. Since this seems to be a known bug with the YAML::XS folks, you can close this as it doesn't seem like there's anything for you to do except maybe document a compatibility limitation?

Thanks for the support!!