thephpleague / json-guard

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

Validating api end-points. #138

Open Danack opened 6 years ago

Danack commented 6 years ago

Hi,

Would it be possible for you to point me in the direction of how to do a couple of things with this library, to validate an api against a swagger schema.

i) Can I validate my generated swagger.json file against the open api specification/schema?

ii) How do I validate api end points. e.g. I have an endpoints like /articles/5 which should return a single article. How do I load up the swagger json file and pass the data to the JsonGuard\Validator, in a way that the validator knows that the data should conform to the ArticleResponse definition.

Thanks in advance for any help.

cheers Dan

matt-allan commented 6 years ago

Hi Danack,

Sorry for the late response! I wrote a whole response the day you posted this but I guess I forgot to save it and closed the tab. I added some answers below just in case it's still useful.

i) Can I validate my generated swagger.json file against the open api specification/schema?

If you are using OpenAPI 2.0 you can use the official schema as the schema and your generated swagger.json as the data, e.g.

<?php

$dereferencer  = League\JsonReference\Dereferencer::draft4();
$schema        = $dereferencer->dereference('file://' . __DIR__ . '/openapi-schema.json'); // the swagger schema
$data          = json_decode(file_get_contents(__DIR__ . '/swagger.json'); // your swagger.json

$validator     = new League\JsonGuard\Validator($data, $schema);

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

ii) How do I validate api end points. e.g. I have an endpoints like /articles/5 which should return a single article. How do I load up the swagger json file and pass the data to the JsonGuard\Validator, in a way that the validator knows that the data should conform to the ArticleResponse definition.

If you are using swagger it's important to note that the swagger schema is not exactly the same as JSON Schema draft 4. There are some keywords like 'discriminator' that won't validate at all. I'm planning on adding swagger rulesets (#122) to make that possible.

That being said you can still validate the request using it if you stick to the subset of keywords that are common to both standards. With swagger your schema is probably at /definitions/ArticleResponse so you can add the pointer as a fragment on the end of the URI, e.g.

<?php

$dereferencer  = new League\JsonReference\Dereferencer();
$schema        = $dereferencer->dereference('file://' . __DIR__ . '/swagger.json#/definitions/ArticleResponse');
$data          = json_decode($request->getContent());

$validator     = new League\JsonGuard\Validator($data, $schema);

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

If you want to get clever you might be able to lookup the URI template the router is using, then use that to look under /paths and grab the response schema automatically. I use that trick to automatically validate responses in my feature tests without having to manually specify the schema each time.

Danack commented 6 years ago

Thanks for the info.

I'm trying to run the swagger validation with the code in the attached files. It appears that I get a stackoverflow when running the code.

Is that something I'm doing wrong, or possibly a bug in the code?

testing.zip

matt-allan commented 6 years ago

Hello,

Thanks for the reproduction code, it's incredibly helpful. It's not looping infinitely for me, it's just incredibly slow. On my machine it is taking 24 seconds to finish validating and collect the errors. There is a benchmark validating the swagger schema against the JSON schema meta schema and it only takes .01 second, so I'm surprised this is so slow. I will need to add a benchmark and see where the bottleneck is.

matt-allan commented 6 years ago

HI Danack,

It looks like your openapi schema is making 140 calls to load json-schema.org/draft-04/schema 😨. It happens during validation because references are resolved lazily.

You can setup caching but I would suggest setting up a custom loader. You can see an example in the tests. I set your testing.php file up like this:

$dereferencer  = JsonDereferencer::draft4();
$dereferencer->getLoaderManager()->registerLoader('http', new ArrayLoader([
    'json-schema.org/draft-04/schema' => file_get_contents(__DIR__ . '/draft4.json')
]));
$schema        = $dereferencer->dereference('file://' . __DIR__ . '/openapi_schema.json');

With that configuration it takes 595ms.