codekie / openapi-examples-validator

Validates embedded examples in OpenAPI-files
MIT License
57 stars 11 forks source link

Allow more external interaction #124

Open DL6ER opened 3 years ago

DL6ER commented 3 years ago

I'm using openapi-example-validator to check if the values returned by our API meet the specifications. This to ensure we cannot forget to update the documentation and to avoid any breaking changes in API output.

Currently, the code does not support much external interaction, e.g., it expects external examples to be present as files. After this PR, we expose two more functions, that may be used by an external script like (fully working example):

const Validator = require('/home/derigs/openapi-examples-validator/src');
const specsFilepath = "test.yaml";

const examples = [
    {string: "somestring", object: {bool: true}},               // OK
    {string: null, object: {bool: false}},                      // OK
    {object: {bool: false}},                                    // string is missing
    {string: "somestring", object: {bool: 123}},                // invalid type
    {string: "somestring", object: {bool: false, extra: 123}},  // extra property
    {object: {bool: 123, extra: 123}},                          // all errors combined
  ];

async function runTests(openApiSpec) {
  for(e in examples) {
    const schemaJsonpath =
      "$.paths./test.get.responses.200.content.application/json.schema";
    const example = examples[e];
    const result = await Validator.validateExampleInline(
      openApiSpec,
      schemaJsonpath,
      example
    );

    if(result.valid !== true) {
      for(i in result.errors) {
        const error = result.errors[i];
        var errormsg = null;
        if(error.keyword === 'additionalProperties')
          errormsg = `${error.message}: ${error.params.additionalProperty} in ${error.dataPath}`;
        else if(error.keyword === 'type')
          errormsg = `${error.message}: ${error.dataPath}`;
        else if(error.keyword === 'required')
          errormsg = `${error.message} in "${error.dataPath}"`;
        else
          errormsg = JSON.stringify(error);
        console.log(`Example ${e}: ${errormsg}`);
      }
    } else {
      console.log(`Example ${e}: OK`);
    }
  }
}

// First, we prepare the OpenAPI spec, then we run the tests on our examples
Validator.prepareOpenapiSpec(specsFilepath, {
  noAdditionalProperties: true,
}).then((openApiSpec) => runTests(openApiSpec));

Output is:

Example 0: OK
Example 1: OK
Example 2: should have required property 'string' in ""
Example 3: should be boolean: ".object.bool"
Example 4: should NOT have additional properties: extra in ".object"
Example 5: should have required property 'string' in ""
Example 5: should be boolean: ".object.bool"
Example 5: should NOT have additional properties: extra in ".object"

I also added tests for the two new functions.

Please mind that this is my very first attempt at anything node-related. I'm happy to improve something if I missed some things.

coveralls commented 3 years ago

Coverage Status

Coverage increased (+0.08%) to 97.79% when pulling ad92336928bca690495500a1e02b8feaeea2f79e on DL6ER:new/example_input into 3795c5e17ded07c816c4e3b5cc48bd41dbcae407 on codekie:master.

codekie commented 3 years ago

Hi @DL6ER . Thank you for your contribution. So far, the API of this library was more like a "hidden feature". While I planned to provide an official API at some point, I didn't want to do that before I've done some major refactoring as I wanted the API to be more stable.

Unfortunately, I'm rather busy with my job at the moment, but I'll have a closer look at this PR once I've got a bit more time.