CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-oas-normalize

Tooling for converting, validating, and parsing OpenAPI, Swagger, and Postman API definitions

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

validation.mddocs/

Validation

Comprehensive validation system with detailed error reporting, contextual messages, and customizable validation rules for OpenAPI, Swagger, and Postman API definitions.

Capabilities

Validate Method

Validate API definitions with comprehensive error reporting and contextual information pointing to specific line numbers and issues.

/**
 * Validate a given API definition with detailed error reporting
 * Supports OpenAPI 3.x, Swagger 2.0, and Postman collections
 * @param opts - Optional validation configuration
 * @returns Promise resolving to validation result if valid, throws ValidationError if invalid
 */
async validate(opts?: {
  parser?: ParserOptions;
}): Promise<ValidationResult>;

interface ValidationResult {
  valid: boolean;
  warnings: WarningDetails[];
  errors: ErrorDetails[];
}

interface ErrorDetails {
  message: string;
  path: string;
  location?: {
    line: number;
    column: number;
  };
}

interface WarningDetails {
  message: string;
  path: string;
  rule: string;
}

Usage Examples:

import OASNormalize from "oas-normalize";

// Basic validation
const oas = new OASNormalize(apiSpec);

try {
  const result = await oas.validate();
  console.log('✅ API definition is valid!');
  if (result.warnings.length > 0) {
    console.warn('⚠️  Warnings found:', result.warnings);
  }
} catch (error) {
  console.error('❌ Validation failed:');
  console.error(error.message);
}
// Validation with custom rules
const oas = new OASNormalize(apiSpec);

try {
  const result = await oas.validate({
    parser: {
      validate: {
        rules: {
          openapi: {
            'path-parameters-not-in-path': 'warning',  // Treat as warning instead of error
            'unused-components': 'off',                // Disable this rule
            'missing-example': 'error'                 // Enforce examples
          }
        }
      }
    }
  });

  if (result.warnings.length) {
    console.warn('🚸 The API is valid but has some warnings:');
    result.warnings.forEach(warning => {
      console.warn(`  - ${warning.message} (${warning.rule})`);
    });
  } else {
    console.log('🍭 The API is valid with no warnings!');
  }
} catch (error) {
  console.error('❌ Validation failed:', error.message);
}

Validation Features

Multi-Format Support

Validates different API definition formats with automatic conversion as needed:

// OpenAPI 3.x validation
const openapi = {
  openapi: "3.0.0",
  info: { title: "Pet Store", version: "1.0.0" },
  paths: {}
};
await new OASNormalize(openapi).validate();

// Swagger 2.0 validation
const swagger = {
  swagger: "2.0",
  info: { title: "Pet Store", version: "1.0.0" },
  paths: {}
};
await new OASNormalize(swagger).validate();

// Postman collection validation (converts to OpenAPI first)
const postman = {
  info: { name: "Collection" },
  item: []
};
await new OASNormalize(postman).validate();

Detailed Error Messages

Validation errors include contextual information with line numbers and specific issue locations:

const invalidSpec = {
  openapi: "3.0.0",
  info: { title: "API" }, // Missing required version field
  servers: [
    { urll: "http://petstore.swagger.io/v2" } // Typo: should be "url"
  ],
  paths: {}
};

try {
  await new OASNormalize(invalidSpec).validate();
} catch (error) {
  console.error(error.message);
  // Output includes:
  // OpenAPI schema validation failed.
  // 
  // REQUIRED must have required property 'version'
  // 
  //    2 |   "info": {
  //  > 3 |     "title": "API"
  //      |     ^ ☹️  version is missing here!
  //    4 |   },
  // 
  // REQUIRED must have required property 'url'
  // 
  //    6 |   "servers": [
  //  > 7 |     {
  //      |     ^ ☹️  url is missing here!
  //    8 |       "urll": "http://petstore.swagger.io/v2"
  //    9 |     }
}

Colorized Error Output

Enable colorized error messages for better readability in terminal environments:

const oas = new OASNormalize(invalidSpec, { 
  colorizeErrors: true 
});

try {
  await oas.validate();
} catch (error) {
  // Error message will include ANSI color codes for:
  // - Red highlighting for error locations
  // - Yellow for warning text
  // - Green for line numbers
  // - Bold formatting for key information
  console.error(error.message);
}

Custom Validation Rules

Rule Configuration

Configure validation behavior with custom rulesets:

const validationOptions = {
  parser: {
    validate: {
      rules: {
        openapi: {
          // Path parameter rules
          'path-parameters-not-in-path': 'warning',
          'path-parameters-defined-but-not-used': 'error',
          
          // Schema rules
          'unused-components': 'warning',
          'missing-example': 'off',
          'schema-names-camel-case': 'error',
          
          // Security rules
          'security-schemes-defined': 'error',
          'security-requirements-defined': 'warning',
          
          // Documentation rules
          'operation-description': 'warning',
          'parameter-description': 'off'
        }
      }
    }
  }
};

const result = await oas.validate(validationOptions);

Rule Severity Levels

  • error: Validation fails, throws ValidationError
  • warning: Validation succeeds but includes warnings in result
  • off: Rule is disabled completely

Available Rules (Examples)

Common OpenAPI validation rules that can be configured:

const commonRules = {
  // Path and parameter validation
  'path-parameters-not-in-path': 'error',
  'path-parameters-defined-but-not-used': 'warning',
  'duplicate-path-parameters': 'error',
  
  // Schema validation
  'unused-components': 'warning',
  'missing-example': 'warning',
  'schema-names-camel-case': 'off',
  'required-properties-schema': 'error',
  
  // Operation validation
  'operation-id-unique': 'error',
  'operation-id-case-convention': 'warning',
  'operation-description': 'warning',
  'operation-summary': 'off',
  
  // Response validation
  'response-schema-defined': 'error',
  'success-response-defined': 'error',
  
  // Security validation
  'security-schemes-defined': 'error',
  'security-requirements-defined': 'warning'
};

Error Handling

ValidationError Class

All validation failures throw ValidationError instances:

import { ValidationError } from "oas-normalize/lib/errors";

try {
  await oas.validate();
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Validation Error:', error.message);
    console.error('Error Name:', error.name); // "ValidationError"
  } else {
    console.error('Unexpected Error:', error);
  }
}

Unsupported Format Handling

const unsupportedSpec = {
  // Missing format indicators
  info: { title: "Unknown" }
};

try {
  await new OASNormalize(unsupportedSpec).validate();
} catch (error) {
  console.error(error.message); // "The supplied API definition is unsupported."
  console.log(error instanceof ValidationError); // true
}

Legacy Format Rejection

const swagger12 = {
  swagger: "1.2",  // Unsupported version
  info: { title: "Old API" }
};

try {
  await new OASNormalize(swagger12).validate();
} catch (error) {
  console.error(error.message); // "Swagger v1.2 is unsupported."
}

Integration with Other Methods

Validation works seamlessly with other OAS Normalize operations:

const oas = new OASNormalize(apiSpec);

// Validate after conversion
const converted = await oas.convert();
await new OASNormalize(converted).validate();

// Validate after bundling
const bundled = await oas.bundle();
await new OASNormalize(bundled).validate();

// Validate after dereferencing
const dereferenced = await oas.dereference();
await new OASNormalize(dereferenced).validate();

// Direct validation (handles conversion internally)
await oas.validate();

Advanced Validation Scenarios

Circular Reference Handling

const specWithCircularRef = {
  openapi: "3.0.0",
  info: { title: "API", version: "1.0.0" },
  components: {
    schemas: {
      Node: {
        type: "object",
        properties: {
          value: { type: "string" },
          child: { $ref: "#/components/schemas/Node" }  // Circular reference
        }
      }
    }
  },
  paths: {}
};

// Circular references are handled gracefully
const result = await new OASNormalize(specWithCircularRef).validate();
console.log('✅ Circular references validated successfully');

External Reference Validation

const specWithExternalRefs = {
  openapi: "3.0.0",
  info: { title: "API", version: "1.0.0" },
  paths: {
    "/pets": {
      get: {
        responses: {
          "200": {
            content: {
              "application/json": {
                schema: { $ref: "./pet-schema.json" }
              }
            }
          }
        }
      }
    }
  }
};

// Validate with external reference resolution
const oas = new OASNormalize(specWithExternalRefs, { enablePaths: true });
await oas.validate(); // Resolves and validates external references

Batch Validation

const specs = [spec1, spec2, spec3];

const validationResults = await Promise.allSettled(
  specs.map(spec => new OASNormalize(spec).validate())
);

validationResults.forEach((result, index) => {
  if (result.status === 'fulfilled') {
    console.log(`✅ Spec ${index + 1} is valid`);
  } else {
    console.error(`❌ Spec ${index + 1} failed:`, result.reason.message);
  }
});

Install with Tessl CLI

npx tessl i tessl/npm-oas-normalize

docs

core-processing.md

error-handling.md

format-conversion.md

index.md

reference-resolution.md

utility-functions.md

validation.md

tile.json