Coder Social home page Coder Social logo

perl-jsonschema-validator's Introduction

NAME

JSONSchema::Validator - Validator for JSON Schema Draft4/Draft6/Draft7 and OpenAPI Specification 3.0

VERSION

version 0.011

SYNOPSIS

# to get OpenAPI validator in YAML format
$validator = JSONSchema::Validator->new(resource => 'file:///some/path/to/oas30.yml');
my ($result, $errors, $warnings) = $validator->validate_request(
    method => 'GET',
    openapi_path => '/user/{id}/profile',
    parameters => {
        path => {
            id => 1234
        },
        query => {
            details => 'short'
        },
        header => {
            header => 'header value'
        },
        cookie => {
            name => 'value'
        },
        body => [$is_exists, $content_type, $data]
    }
);
my ($result, $errors, $warnings) = $validator->validate_response(
    method => 'GET',
    openapi_path => '/user/{id}/profile',
    status => '200',
    parameters => {
        header => {
            header => 'header value'
        },
        body => [$is_exists, $content_type, $data]
    }
)

# to get JSON Schema Draft4/Draft6/Draft7 validator in JSON format
$validator = JSONSchema::Validator->new(resource => 'http://example.com/draft4/schema.json')
my ($result, $errors) = $validator->validate_schema($object_to_validate)

DESCRIPTION

OpenAPI specification and JSON Schema Draft4/Draft6/Draft7 validators with minimum dependencies.

METHODS

new

Creates one of the following validators: JSONSchema::Validator::Draft4, JSONSchema::Validator::Draft6, JSONSchema::Validator::Draft7, JSONSchema::Validator::OAS30.

my $validator = JSONSchema::Validator->new(resource => 'file:///some/path/to/oas30.yml');
my $validator = JSONSchema::Validator->new(resource => 'http://example.com/draft4/schema.json');
my $validator = JSONSchema::Validator->new(schema => {'$schema' => 'path/to/schema', ...});
my $validator = JSONSchema::Validator->new(schema => {...}, specification => 'Draft4');

if parameter specification is not specified then type of validator will be determined by $schema key for JSON Schema Draft4/Draft6/Draft7 and by openapi key for OpenAPI Specification 3.0 in schema parameter.

Parameters:

  • resources

    To get schema by uri

  • schema

    To get explicitly specified schema

  • specification

    To specify specification of schema

  • validate_schema

    Do not validate specified schema

  • base_uri

    To specify base uri of schema. This parameter used to build absolute path by relative reference in schema. By default base_uri is equal to the resource path if the resource parameter is specified otherwise the $id key in the schema.

Additional parameters need to be looked at in a specific validator class. Currently there are validators: JSONSchema::Validator::Draft4, JSONSchema::Validator::Draft6, JSONSchema::Validator::Draft7, JSONSchema::Validator::OAS30.

validate_paths

Validates all files specified by path globs.

my $result = JSONSchema::Validator->validate_paths(['/some/path/to/openapi.*.yaml', '/some/path/to/jsonschema.*.json']);
for my $file (keys %$result) {
    my ($res, $errors) = @{$result->{$file}};
}

validate_resource

validate_resource_schema

CAVEATS

YAML & booleans

When reading schema definitions from YAML, please note that the standard behaviour of YAML::PP and YAML::XS is to read values which evaluate to true or false in a perl context. These values have no recognizable 'boolean type'. This is insufficient for JSON schema validation.

To make the YAML readers and booleans work with JSONSchema::Validator, you need to use the JSON::PP (included in Perl's standard library) module as follows:

# for YAML::PP
use YAML::PP;

my $reader = YAML::PP->new( boolean => 'JSON::PP' );
# from here, you can freely use the reader to
# read & write booleans as 'true' and 'false'


# for YAML::XS
use YAML::XS;

my $reader = YAML::XS->new;

# and whenever you read YAML with this reader, do:
my $yaml = do {
  local $YAML::XS::Boolean = 'JSON::PP';
  $reader->Load($string); # or $reader->LoadFile('filename');
};

This isn't a problem when you use the resource argument to the JSONSchema::Validator::new constructor, but if you read your own schema and use the schema argument, this is something to be aware of.

allow_bignum => 1

The allow_bignum = 1> setting (available on JSON::XS and Cpanel::JSON::XS) on deserializers is not supported.

When deserializing a request body with a JSON parser configured with allow_bignum = 1>, floats - even ones which fit into the regular float ranges - will be deserialized as Math::BigFloat. Similarly, integers outside of the internal integer range are deserialized as Math::BigInt. Numbers represented as Math::Big* objects are not recognized as actual numbers and will fail validation.

AUTHORS

CONTRIBUTORS

COPYRIGHT AND LICENSE

This software is Copyright (c) 2021 by Alexey Stavrov.

This is free software, licensed under:

The MIT (X11) License

perl-jsonschema-validator's People

Contributors

logioniz avatar dionys avatar ehuelsmann avatar avkhozov avatar uid66 avatar arxa1l avatar j-waters avatar

Stargazers

Nikos Vaggalis avatar Ovid avatar Peter Mottram avatar grothja avatar  avatar  avatar  avatar Anton avatar

Watchers

 avatar James Cloos avatar Alexey Kirpichnikov avatar  avatar  avatar  avatar  avatar  avatar

perl-jsonschema-validator's Issues

Use of uninitialized value $scheme

When the validator constructor is passed a file name, not a URL, perl reports errors for the module:

my $validator = JSONSchema::Validator->new(resource => 'some.yaml');

gives

Use of uninitialized value $scheme in exists at /usr/pkg/lib/perl5/vendor_perl/5.34.0/JSONSchema/Validator/Util.pm line 125.
Use of uninitialized value $scheme in string eq at /usr/pkg/lib/perl5/vendor_perl/5.34.0/JSONSchema/Validator/Util.pm line 127.
Unsupported scheme of uri some.yaml at /usr/pkg/lib/perl5/vendor_perl/5.34.0/JSONSchema/Validator.pm line 112.

Plan to add OAS 3.1

OpenAPI 3.1 specification based on JSON Schema Draft 2020-12.

It looks like that first thing that need to do is add support for draft 2020-12.

Along the way, I decided to implement a draft6, draft7, draft 2019-09.

How do I convert "wrong content_type" error to HTTP_UNSUPPORTED_MEDIA_TYPE (415)

Hi,

When validating requests against an OpenAPI 3.0 specification, the library may return this error:

return 0, [error(message => qq{content with content-type $content_type is omit in schema})], [];

in my code, I'd like to convert this error to an HTTP_UNSUPPORTED_MEDIA_TYPE status code in the HTTP response. I'm currently reporting HTTP_BAD_REQUEST (400) on all validation errors, but 415 exists specifically for the purpose of reporting this error.

Would it be possible to add a code to the error message which helps me identify this specific error? I'd rather avoid using the error message itself, because that could change in the future. Maybe something like this:

   return 0, [error(message => q|the message|, code => 'unspecified_content_type'), [];

?

Fail to reject zero-length parameter specified to be minimally length == 1

The schema at

https://github.com/ehuelsmann/LedgerSMB/blob/7706a22fc3f3e3271f45f57f14e3ced54db6d5bd/lib/LedgerSMB/Routes/ERP/API/Invoices.pm#L1068-L1075

is supposed to reject/fail validation of a request to the URI Path /invoices/ (note the ending slash) within the API URL namespace of the installation (usually /erp/api/v0/). The request to /invoices/ has a zero-length (empty string) parameter id. With the validation condition saying "minimal length 1".

Schema validation fails when loading with own YAML::PP instance

I have this file below, with the embedded schema in the __DATA__ section. https://editor.swagger.io thinks the schema is completely acceptable (I copy-pasted it in there), but JSONSchema-Validator fails with the following log:

invalid schema:
instance is not valid under any of given schemas of "oneOf" [instance path: /paths/~1erp~1api~1invoices/post/responses/201] [schema path: /properties/paths/$ref/patternProperties/^\~1/$ref/patternProperties/^(get|put|post|delete|options|head|patch|trace)$/$ref/properties/responses/$ref/patternProperties/^[1-5](?:\d{2}|XX)$/oneOf]
instance is not valid under any of given schemas of "oneOf" [instance path: /paths/~1erp~1api~1invoices/post/requestBody] [schema path: /properties/paths/$ref/patternProperties/^\~1/$ref/patternProperties/^(get|put|post|delete|options|head|patch|trace)$/$ref/properties/requestBody/oneOf]
instance is not valid under any of given schemas of "oneOf" [instance path: /paths/~1erp~1api~1invoices~1{id}/parameters/0] [schema path: /properties/paths/$ref/patternProperties/^\~1/$ref/properties/parameters/items/oneOf] at t.pl line 14.

Doing the comparison between the indicated meta schema paths and the schema instance document, I can only but conclude that the schema is correct.

use strict;
use warnings;

use JSONSchema::Validator;
use YAML::PP;

my $reader = YAML::PP->new;
local $/;
my $yml = <DATA>;


my $schema = $reader->load_string($yml);
my $validator = JSONSchema::Validator->new(
    schema => $schema,
    specification => 'OAS30');

__DATA__
openapi: 3.0.0
info:
  title: ...
  version: 0.0.1
paths:
  /erp/api/invoices:
    get:
      responses:
        200:
          description: ...
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Invoice'
        default:
          description: ...
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error'
    post:
      requestBody:
        description: ...
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/newInvoice'
      responses:
        201:
          description: Created
          headers:
            Location:
              description: ...
              required: true
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Invoice'
  /erp/api/invoices/{id}:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
    get:
      responses:
        200:
          description: ...
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Invoice'
    put:
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/newInvoice'
      responses:
        200:
          description: ...
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Invoice'
components:
  schemas:
    error:
      type: object
    newInvoice:
      type: object
      required:
        - eca
        - account
        - currency
      properties:
        eca:
          anyOf:
            - type: object
              required:
                - id
              properties:
                id:
                  type: integer
                  format: int64
                  minimum: 1
            - type: object
              required:
                - number
                - type
              properties:
                number:
                  type: string
                type:
                  type: string
                  enum:
                    - customer
                    - vendor
        account:
          type: string
        currency:
          type: string
          minLength: 3
          maxLength: 3
        description:
          type: string
        notes:
          type: string
        internal-notes:
          type: string
        invoice-number:
          type: string
        order-number:
          type: string
        po-number:
          type: string
        ship-via:
          type: string
        shipping-point:
          type: string
        ship-to:
          type: object
        dates:
          type: object
          properties:
            due:
              type: string
              format: date
            book:
              type: string
              format: date
            created:
              type: string
              format: date
        lines:
          type: array
          items:
            type: object
            required:
              - part
            properties:
              description:
                type: string
              price:
                type: number
              price_fixated:
                type: boolean
                default: false
              unit:
                type: string
              qty:
                type: number
                default: 1
              taxform:
                type: boolean
                default: false
              serialnumber:
                type: string
              discount:
                type: number
              discount_type:
                type: string
                enum:
                  - '%'
              delivery_date:
                type: string
                format: date
              part:
                type: object
                required:
                  - number
                properties:
                  number:
                    type: string
                    minLength: 1
        taxes:
          type: array
          items:
            type: object
            additionalProperties:
              type: object
              properties:
                tax:
                  type: object
                  required:
                    - category
                  properties:
                    category:
                      type: string
                    base-amount:
                      type: number
                    amount:
                      type: number
                    source:
                      type: string
                    memo:
                      type: string
        payments:
          type: array
          items:
            type: object
            required:
              - account
              - amount
              - date
            properties:
              date:
                type: string
                format: date
              source:
                type: string
              memo:
                type: string
              amount:
                type: number
              account:
                type: object
                properties:
                  accno:
                    type: string
    Invoice:
      description: ...
      allOf:
        - $ref: '#/components/schemas/newInvoice'
        - type: object
          properties:
            eca:
              type: object
              properties:
                entity:
                  type: object
                  properties:
                    credit_limit:
                      type: object
                      properties:
                        total:
                          type: number
                        used:
                          type: number
                        available:
                          type: number
            account:
              type: object
              properties:
                description:
                  type: string
            lines:
              type: array
              items:
                type: object
                properties:
                  part:
                    type: object
                    properties:
                      _self:
                        type: string
                  total:
                    type: number
            taxes:
              type: object
              additionalProperties:
                type: object
                properties:
                  name:
                    type: string
                  rate:
                    type: number
                    minimum: 0
                    maximum: 1
                  calculated-amount:
                    type: number
            payments:
              type: array
              items:
                type: object
                properties:
                  account:
                    type: object
                    properties:
                      description:
                        type: string

Please provide me with help on where to start debugging, both in my schema as well as in the library code, so I can start figuring out why the error is reported and either fix the schema or submit a PR for the library.

Thanks!

"cpanm JSONSchema::Validator" fails due to missing "Test::CPAN::Changes" dependency

The log is:

Searching JSONSchema::Validator () on cpanmetadb ...
--> Working on JSONSchema::Validator
Fetching http://www.cpan.org/authors/id/L/LO/LOGIONIZ/JSONSchema-Validator-0.010.tar.gz
-> OK
Unpacking JSONSchema-Validator-0.010.tar.gz
Entering JSONSchema-Validator-0.010
Checking configure dependencies from META.json
Checking if you have ExtUtils::MakeMaker 6.58 ... Yes (7.44)
Configuring JSONSchema-Validator-0.010
Running Makefile.PL
Checking if your kit is complete...
Looks good
Generating a Unix-style Makefile
Writing Makefile for JSONSchema::Validator
Writing MYMETA.yml and MYMETA.json
-> OK
Checking dependencies from MYMETA.json ...
Checking if you have parent 0 ... Yes (0.238)
Checking if you have utf8 0 ... Yes (1.22)
Checking if you have URI 1.00 ... Yes (5.08)
Checking if you have Cwd 0 ... Yes (3.78)
Checking if you have IPC::Open3 0 ... Yes (1.21)
Checking if you have Scalar::Util 0 ... Yes (1.55)
Checking if you have ExtUtils::MakeMaker 0 ... Yes (7.44)
Checking if you have B 0 ... Yes (1.80)
Checking if you have re 0 ... Yes (0.40)
Checking if you have Carp 0 ... Yes (1.50)
Checking if you have File::Basename 0 ... Yes (2.85)
Checking if you have IO::Handle 0 ... Yes (1.42)
Checking if you have File::Spec 0 ... Yes (3.78)
Checking if you have overload 0 ... Yes (1.31)
Checking if you have JSON::PP 0 ... Yes (4.06)
Checking if you have strict 0 ... Yes (1.11)
Checking if you have Encode 0 ... Yes (3.06)
Checking if you have warnings 0 ... Yes (1.47)
Checking if you have lib 0 ... Yes (0.65)
Checking if you have Time::Piece 0 ... Yes (1.3401)
Checking if you have constant 0 ... Yes (1.33)
Checking if you have Test::More 0 ... Yes (1.302183)
Building and testing JSONSchema-Validator-0.010
cp lib/JSONSchema/Validator/Constraints/Draft4.pm blib/lib/JSONSchema/Validator/Constraints/Draft4.pm
cp lib/JSONSchema/Validator/JSONPointer.pm blib/lib/JSONSchema/Validator/JSONPointer.pm
cp lib/JSONSchema/Validator/schemas/oas30.json blib/lib/JSONSchema/Validator/schemas/oas30.json
cp lib/JSONSchema/Validator/Constraints/Draft7.pm blib/lib/JSONSchema/Validator/Constraints/Draft7.pm
cp lib/JSONSchema/Validator/Constraints/Draft6.pm blib/lib/JSONSchema/Validator/Constraints/Draft6.pm
cp lib/JSONSchema/Validator/Constraints/OAS30.pm blib/lib/JSONSchema/Validator/Constraints/OAS30.pm
cp lib/JSONSchema/Validator/Format.pm blib/lib/JSONSchema/Validator/Format.pm
cp lib/JSONSchema/Validator/schemas/draft7.json blib/lib/JSONSchema/Validator/schemas/draft7.json
cp lib/JSONSchema/Validator/Util.pm blib/lib/JSONSchema/Validator/Util.pm
cp lib/JSONSchema/Validator/schemas/draft4.json blib/lib/JSONSchema/Validator/schemas/draft4.json
cp lib/JSONSchema/Validator/schemas/draft6.json blib/lib/JSONSchema/Validator/schemas/draft6.json
cp lib/JSONSchema/Validator/Draft4.pm blib/lib/JSONSchema/Validator/Draft4.pm
cp lib/JSONSchema/Validator/Error.pm blib/lib/JSONSchema/Validator/Error.pm
cp lib/JSONSchema/Validator.pm blib/lib/JSONSchema/Validator.pm
cp lib/JSONSchema/Validator/URIResolver.pm blib/lib/JSONSchema/Validator/URIResolver.pm
cp lib/JSONSchema/Validator/Draft7.pm blib/lib/JSONSchema/Validator/Draft7.pm
cp lib/JSONSchema/Validator/Draft6.pm blib/lib/JSONSchema/Validator/Draft6.pm
cp lib/JSONSchema/Validator/OAS30.pm blib/lib/JSONSchema/Validator/OAS30.pm
Manifying 14 pod documents
PERL_DL_NONLAZY=1 "/usr/bin/perl" "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/00-compile.t ............... ok
t/acceptance.t ............... skipped: these tests are for testing by the developer
t/author-critic.t ............ skipped: these tests are for testing by the author
t/author-pod-spell.t ......... skipped: these tests are for testing by the author
t/format.t ................... ok
t/json_schema.t .............. ok
t/oas.t ...................... ok
Can't locate Test/CPAN/Changes.pm in @INC (you may need to install the Test::CPAN::Changes module) (@INC contains: /root/.cpanm/work/1654966602.413/JSONSchema-Validator-0.010/blib/lib /root/.cpanm/work/1654966602.413/JSONSchema-Validator-0.010/blib/arch lib old/lib lib old/lib /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.32.1 /usr/local/share/perl/5.32.1 /usr/lib/x86_64-linux-gnu/perl5/5.32 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.32 /usr/share/perl/5.32 /usr/local/lib/site_perl .) at t/release-cpan-changes.t line 15.
BEGIN failed--compilation aborted at t/release-cpan-changes.t line 15.
# Looks like your test exited with 2 before it could output anything.
t/release-cpan-changes.t ..... 
Dubious, test returned 2 (wstat 512, 0x200)
Failed 1/1 subtests 
t/validator_json_schema.t .... ok
t/validator_oas.t ............ ok
t/validator_validate_path.t .. ok

Test Summary Report
-------------------
t/release-cpan-changes.t   (Wstat: 512 Tests: 0 Failed: 0)
  Non-zero exit status: 2
  Parse errors: Bad plan.  You planned 1 tests but ran 0.
Files=11, Tests=1231,  2 wallclock secs ( 0.11 usr  0.01 sys +  1.87 cusr  0.25 csys =  2.24 CPU)
Result: FAIL
Failed 1/11 test programs. 0/1231 subtests failed.
make: *** [Makefile:925: test_dynamic] Error 255
-> FAIL Installing JSONSchema::Validator failed. See ~/.cpanm/work/1654966602.413/build.log for details. Retry with --force to force install it.

Required header not validated when `header` not passed

A schema which requires a specific header in a request (e.g. ETag), will successfully validate, even if it can't validate the headers, because the header parameter is missing.

There are two possible solutions:

  1. Throw an error right at the start, when the user parameters are being wrapped, explaining the schema requires validation of parameters of type header (or any of the others) and that the type isn't passed in
  2. Generate empty values for all headers/url parameters/... the library tries to validate.

Both are a small change. Let me know which you prefer.

I personally prefer (1), because it's most clear to the programmer what's the problem that needs solving.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.