CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-openapi3-ts

TypeScript models and utilities for building OpenAPI 3.x specification documents with fluent DSL builder pattern

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

specification-extensions.mddocs/

Specification Extensions

Support for OpenAPI specification extensions (x-* properties) with validation and management utilities.

Capabilities

Extension Type Definitions

Core types for working with OpenAPI specification extensions.

/**
 * Extension name pattern - must start with 'x-'
 */
type IExtensionName = `x-${string}`;

/**
 * Extension value type - can be any value
 */
type IExtensionType = any;

/**
 * Interface for objects supporting specification extensions
 */
interface ISpecificationExtension {
  [extensionName: IExtensionName]: IExtensionType;
}

SpecificationExtension Class

Implementation class for managing OpenAPI specification extensions.

/**
 * Specification extension management class
 */
class SpecificationExtension implements ISpecificationExtension {
  [extensionName: IExtensionName]: any;
  
  /**
   * Validate if an extension name follows the x- pattern
   * @param extensionName - Extension name to validate
   * @returns True if extension name is valid (starts with 'x-')
   */
  static isValidExtension(extensionName: string): boolean;
  
  /**
   * Get an extension value by name
   * @param extensionName - Extension name (must start with 'x-')
   * @returns Extension value or null if not found
   * @throws Error if extension name is invalid
   */
  getExtension(extensionName: string): any;
  
  /**
   * Add an extension with validation
   * @param extensionName - Extension name (must start with 'x-')
   * @param payload - Extension value
   * @throws Error if extension name is invalid
   */
  addExtension(extensionName: string, payload: any): void;
  
  /**
   * List all extension names on this object
   * @returns Array of extension names
   */
  listExtensions(): string[];
}

Usage Examples:

import { SpecificationExtension } from "openapi3-ts";

// Create extension manager
const extensions = new SpecificationExtension();

// Add extensions
extensions.addExtension("x-custom-field", "custom value");
extensions.addExtension("x-rate-limit", { requests: 100, window: "1m" });
extensions.addExtension("x-internal-id", 12345);

// Get extension values
const customField = extensions.getExtension("x-custom-field");
console.log(customField); // "custom value"

const rateLimit = extensions.getExtension("x-rate-limit");
console.log(rateLimit); // { requests: 100, window: "1m" }

// List all extensions
const extensionNames = extensions.listExtensions();
console.log(extensionNames); // ["x-custom-field", "x-rate-limit", "x-internal-id"]

// Validate extension names
console.log(SpecificationExtension.isValidExtension("x-valid")); // true
console.log(SpecificationExtension.isValidExtension("invalid")); // false

// Error handling
try {
  extensions.addExtension("invalid-name", "value");
} catch (error) {
  console.error(error.message); // "Invalid specification extension..."
}

Utility Functions

Helper functions for working with extensions on any OpenAPI object.

/**
 * Get an extension value from any object supporting extensions
 * @param obj - Object with potential extensions
 * @param extensionName - Extension name (must start with 'x-')
 * @returns Extension value or undefined
 */
function getExtension(
  obj: ISpecificationExtension | undefined,
  extensionName: string
): any;

/**
 * Add an extension to any object supporting extensions
 * @param obj - Object to add extension to
 * @param extensionName - Extension name (must start with 'x-')
 * @param extension - Extension value
 */
function addExtension(
  obj: ISpecificationExtension | undefined,
  extensionName: string,
  extension: any
): void;

Usage Examples:

import { oas30, getExtension, addExtension } from "openapi3-ts";

// Create OpenAPI objects
const schema: oas30.SchemaObject = {
  type: "object",
  properties: {
    id: { type: "integer" }
  }
};

const operation: oas30.OperationObject = {
  summary: "Get item",
  responses: {
    "200": { description: "Success" }
  }
};

// Add extensions using utility functions
addExtension(schema, "x-database-table", "items");
addExtension(schema, "x-validation-level", "strict");

addExtension(operation, "x-rate-limit", 1000);
addExtension(operation, "x-cached", true);

// Get extensions using utility functions
const tableName = getExtension(schema, "x-database-table");
console.log(tableName); // "items"

const rateLimit = getExtension(operation, "x-rate-limit");
console.log(rateLimit); // 1000

// Extensions are accessible as properties too
console.log(schema["x-validation-level"]); // "strict"
console.log(operation["x-cached"]); // true

Extension Patterns and Examples

Common Extension Patterns

import { oas30 } from "openapi3-ts";

// Vendor-specific extensions
const spec = oas30.OpenApiBuilder.create()
  .addTitle("API with Extensions")
  .addVersion("1.0.0")
  .getSpec();

// Add vendor extensions to the root document
spec["x-amazon-apigateway-cors"] = {
  allowOrigins: ["*"],
  allowMethods: ["GET", "POST"],
  allowHeaders: ["Content-Type", "Authorization"]
};

spec["x-swagger-ui"] = {
  theme: "dark",
  displayRequestDuration: true
};

// Schema-level extensions for code generation
const userSchema: oas30.SchemaObject = {
  type: "object",
  required: ["id", "name"],
  properties: {
    id: { type: "integer", format: "int64" },
    name: { type: "string" },
    email: { type: "string", format: "email" }
  }
};

// Add code generation hints
userSchema["x-go-type"] = "User";
userSchema["x-java-class"] = "com.example.User";
userSchema["x-database-table"] = "users";
userSchema["x-tags"] = ["entity", "user"];

// Operation-level extensions for infrastructure
const getUserOperation: oas30.OperationObject = {
  summary: "Get user by ID",
  parameters: [
    {
      name: "id",
      in: "path",
      required: true,
      schema: { type: "integer" }
    }
  ],
  responses: {
    "200": {
      description: "User found",
      content: {
        "application/json": {
          schema: { $ref: "#/components/schemas/User" }
        }
      }
    }
  }
};

// Add infrastructure extensions
getUserOperation["x-rate-limit"] = { requests: 100, window: "1m" };
getUserOperation["x-cache-ttl"] = 300; // 5 minutes
getUserOperation["x-auth-required"] = true;
getUserOperation["x-permissions"] = ["user:read"];

Extension Validation and Management

import { SpecificationExtension, ISpecificationExtension } from "openapi3-ts";

// Helper class for managing typed extensions
class ExtensionManager {
  private extensions: ISpecificationExtension = {};
  
  addRateLimit(requests: number, window: string): void {
    this.extensions["x-rate-limit"] = { requests, window };
  }
  
  addCacheSettings(ttl: number, strategy: string): void {
    this.extensions["x-cache"] = { ttl, strategy };
  }
  
  addVendorConfig(vendor: string, config: object): void {
    const extensionName = `x-${vendor}-config` as any;
    if (SpecificationExtension.isValidExtension(extensionName)) {
      this.extensions[extensionName] = config;
    }
  }
  
  applyTo(target: ISpecificationExtension): void {
    Object.keys(this.extensions).forEach(key => {
      if (SpecificationExtension.isValidExtension(key)) {
        target[key as any] = this.extensions[key as any];
      }
    });
  }
  
  getExtensions(): ISpecificationExtension {
    return { ...this.extensions };
  }
}

// Usage
const extManager = new ExtensionManager();
extManager.addRateLimit(1000, "1h");
extManager.addCacheSettings(600, "lru");
extManager.addVendorConfig("aws", {
  region: "us-east-1",
  timeout: 30000
});

// Apply to OpenAPI objects
const operation: oas30.OperationObject = {
  summary: "Test operation",
  responses: { "200": { description: "Success" } }
};

extManager.applyTo(operation);
console.log(operation["x-rate-limit"]); // { requests: 1000, window: "1h" }
console.log(operation["x-aws-config"]); // { region: "us-east-1", timeout: 30000 }

Extension Integration with Builders

import { oas30, SpecificationExtension } from "openapi3-ts";

// Extend builder with extension support
class ExtendedOpenApiBuilder extends oas30.OpenApiBuilder {
  addExtension(extensionName: string, value: any): ExtendedOpenApiBuilder {
    if (SpecificationExtension.isValidExtension(extensionName)) {
      this.rootDoc[extensionName as any] = value;
    } else {
      throw new Error(`Invalid extension name: ${extensionName}`);
    }
    return this;
  }
  
  addSchemaWithExtensions(
    name: string, 
    schema: oas30.SchemaObject,
    extensions: { [key: string]: any }
  ): ExtendedOpenApiBuilder {
    // Add extensions to schema
    Object.keys(extensions).forEach(key => {
      if (SpecificationExtension.isValidExtension(key)) {
        (schema as any)[key] = extensions[key];
      }
    });
    
    return this.addSchema(name, schema) as ExtendedOpenApiBuilder;
  }
  
  addOperationWithExtensions(
    path: string,
    method: string,
    operation: oas30.OperationObject,
    extensions: { [key: string]: any }
  ): ExtendedOpenApiBuilder {
    // Add extensions to operation
    Object.keys(extensions).forEach(key => {
      if (SpecificationExtension.isValidExtension(key)) {
        (operation as any)[key] = extensions[key];
      }
    });
    
    const pathItem: oas30.PathItemObject = {
      [method]: operation
    };
    
    return this.addPath(path, pathItem) as ExtendedOpenApiBuilder;
  }
}

// Usage
const spec = new ExtendedOpenApiBuilder()
  .addTitle("Extended API")  
  .addVersion("1.0.0")
  .addExtension("x-api-id", "api-12345")
  .addExtension("x-build-info", {
    version: "1.2.3",
    buildTime: new Date().toISOString(),
    gitCommit: "abc123"
  })
  .addSchemaWithExtensions("User", {
    type: "object",
    properties: {
      id: { type: "integer" },
      name: { type: "string" }
    }
  }, {
    "x-database-table": "users",
    "x-java-class": "com.example.User"
  })
  .addOperationWithExtensions("/users", "get", {
    summary: "List users",
    responses: {
      "200": { description: "Success" }
    }
  }, {
    "x-rate-limit": { requests: 100, window: "1m" },
    "x-cache-ttl": 300
  })
  .getSpec();

console.log(spec["x-api-id"]); // "api-12345"
console.log(spec.components?.schemas?.User?.["x-database-table"]); // "users"

Best Practices

Extension Naming Conventions

// Good extension names
const goodExtensions = [
  "x-internal-id",        // kebab-case
  "x-rate-limit",         // descriptive
  "x-vendor-config",      // vendor prefix
  "x-code-gen-options",   // purpose clear
];

// Poor extension names  
const poorExtensions = [
  "x-data",               // too generic
  "x-temp",               // unclear purpose
  "x-customField",        // camelCase (prefer kebab)
  "x-123",                // starts with number
];

// Validation helper
function isGoodExtensionName(name: string): boolean {
  return SpecificationExtension.isValidExtension(name) &&
         name.length > 2 &&
         /^x-[a-z][a-z0-9-]*$/.test(name);
}

Type-Safe Extension Handling

import { ISpecificationExtension } from "openapi3-ts";

// Define typed extension interfaces
interface RateLimitExtension {
  "x-rate-limit": {
    requests: number;
    window: string;
  };
}

interface CacheExtension {
  "x-cache-ttl": number;
}

// Utility types for extension combinations
type WithRateLimit<T> = T & RateLimitExtension;
type WithCache<T> = T & CacheExtension;
type WithBoth<T> = T & RateLimitExtension & CacheExtension;

// Type-safe extension helpers
function addRateLimit<T extends ISpecificationExtension>(
  obj: T, 
  requests: number, 
  window: string
): WithRateLimit<T> {
  (obj as any)["x-rate-limit"] = { requests, window };
  return obj as WithRateLimit<T>;
}

function addCache<T extends ISpecificationExtension>(
  obj: T,
  ttl: number  
): WithCache<T> {
  (obj as any)["x-cache-ttl"] = ttl;
  return obj as WithCache<T>;
}

// Usage with type safety
import { oas30 } from "openapi3-ts";

let operation: oas30.OperationObject = {
  summary: "Get user",
  responses: { "200": { description: "Success" } }
};

// Chain extensions with type safety
operation = addCache(addRateLimit(operation, 100, "1m"), 300);

// TypeScript knows about the extensions
console.log(operation["x-rate-limit"].requests); // 100
console.log(operation["x-cache-ttl"]); // 300

Install with Tessl CLI

npx tessl i tessl/npm-openapi3-ts

docs

index.md

openapi30-builder.md

openapi30-types.md

openapi31-builder.md

openapi31-types.md

server-management.md

specification-extensions.md

tile.json