A TypeScript/Node.js package to intelligently reduce OpenAPI schemas to a specified number of operations and size limit.
- ✨ Smart Prioritization: Intelligently selects the most important operations based on entity importance and operation type
- đź§™ Interactive Wizard: Manually select operations by groups/tags or individually with undo support
- 📦 Size Optimization: Automatically reduces schema size by removing examples and truncating descriptions
- đź”§ Flexible Configuration: Customize via CLI flags or config file (
.spec-shaver.json) - 🎯 Schema Validity: Automatically includes all referenced schemas and validates output
- 🚀 CLI Tool: Easy-to-use command-line interface with color-coded output
- 📊 Progress Indicators: Real-time feedback with spinners and progress messages
- 🔍 Verbose Mode: Detailed logging for debugging and understanding operations
- âś… Validation: Ensures reduced schemas are valid OpenAPI specifications
- 📚 Programmatic API: Use as a library in your own code
| Command | Selection | Best For |
|---|---|---|
reduce |
Automatic | Quick reduction with algorithmic prioritization |
wizard |
Interactive | Manual control - select by groups or individual endpoints |
fetch |
Automatic | Fetching and reducing remote schemas via URL |
npm install spec-shaver
# or
pnpm add spec-shaver
# or
yarn add spec-shaverCreate a .spec-shaver.json config file in your project:
npx spec-shaver initThis creates a default config file you can customize:
{
"maxActions": 30,
"maxSizeBytes": 1048576,
"coreEntities": ["users", "accounts", "organizations"],
"includeExamples": false,
"maxDescriptionLength": 200,
"output": "reduced_schema.json"
}Then run commands without repeating options:
npx spec-shaver reduce --input schema.json# Install dependencies
pnpm install
# Build and run
pnpm dev reduce --input schema.json --output reduced.json
# Or build first, then run
pnpm build
pnpm start reduce --input schema.json --output reduced.json
# Or run directly with node
node dist/cli.js reduce --input schema.jsonnpx spec-shaver reduce --input schema.json --output reduced.jsonFetch and reduce from a URL:
npx spec-shaver fetch --url https://api.example.com/openapi.jsonInteractive wizard - select exactly which endpoints to keep:
npx spec-shaver wizard --input schema.json --output reduced.jsonimport { OpenAPIReducer, SchemaFetcher } from 'spec-shaver';
import * as fs from 'fs';
// Load your OpenAPI schema
const schemaContent = fs.readFileSync('openapi.json', 'utf8');
const schema = JSON.parse(schemaContent);
// Create reducer with options
const reducer = new OpenAPIReducer({
maxActions: 30,
maxSizeBytes: 1024 * 1024, // 1MB
coreEntities: ['users', 'orders', 'products'],
includeExamples: false,
});
const result = reducer.reduce(schema);
console.log(`Reduced to ${result.reducedOperationCount} operations`);
console.log(`Size: ${(result.sizeBytes / 1024 / 1024).toFixed(2)} MB`);
// Or fetch from a URL
const remoteSchema = await SchemaFetcher.fetch({ url: 'https://api.example.com/openapi.json' });
const remoteResult = reducer.reduce(remoteSchema);All commands support these global options:
-v, --verbose Enable verbose logging (detailed operation info)
-q, --quiet Suppress all output except errors
-c, --config <file> Path to config file (default: .spec-shaver.json)spec-shaver init [options]
Options:
-o, --output <file> Config file path (default: ".spec-shaver.json")Example:
spec-shaver init
# Creates .spec-shaver.json with default settingsspec-shaver reduce [options]
Options:
-i, --input <file> Input schema file (required)
-o, --output <file> Output file path (default: "reduced_schema.json")
-a, --actions <number> Maximum number of actions (default: 30)
-s, --size <bytes> Maximum size in bytes (default: 1048576)
-m, --methods <methods> Filter by HTTP methods (comma-separated, e.g., "get,post")
--include-examples Include examples in schema (default: false)
--resolve-refs Resolve all $ref references by inlining them (default: false)
-h, --help Display helpExample:
# Basic usage
spec-shaver reduce --input original-schema.json --output reduced-schema.json
# With verbose logging
spec-shaver reduce -v --input schema.json --actions 20
# Using config file
spec-shaver reduce --input schema.json --config my-config.json
# Quiet mode (only errors)
spec-shaver reduce -q --input schema.jsonspec-shaver fetch [options]
Options:
-u, --url <url> URL to fetch OpenAPI schema from (required)
-H, --header <header...> HTTP headers (format: "Key: Value")
-o, --output <file> Output file path (default: "reduced_schema.json")
-a, --actions <number> Maximum number of actions (default: 30)
-s, --size <bytes> Maximum size in bytes (default: 1048576)
-m, --methods <methods> Filter by HTTP methods (comma-separated, e.g., "get,post")
--include-examples Include examples in schema (default: false)
--resolve-refs Resolve all $ref references by inlining them (default: false)
-h, --help Display helpExample:
# Fetch from URL
spec-shaver fetch --url https://api.example.com/openapi.json
# With authentication
spec-shaver fetch \
--url https://api.example.com/openapi.json \
--header "Authorization: Bearer YOUR_TOKEN" \
--output my-schema.json
# With verbose logging
spec-shaver fetch -v --url https://api.example.com/openapi.json --actions 25The wizard lets you interactively select which operations to include:
spec-shaver wizard [options]
Options:
-i, --input <file> Input schema file
-u, --url <url> URL to fetch OpenAPI schema from
-H, --header <header...> HTTP headers for URL fetch
-o, --output <file> Output file path (default: "reduced_schema.json")
--include-examples Include examples in schema (default: false)
--resolve-refs Resolve all $ref references by inlining them (default: false)
-h, --help Display helpThe wizard offers three selection modes:
- Select by groups/tags - Choose entire groups of related endpoints
- Select individual operations - Pick specific endpoints one by one
- Keep all operations - Include everything (only optimize size)
New in v1.1: Navigate back through wizard steps with the "Go back" option!
Example:
# Interactive selection from file
spec-shaver wizard --input openapi.json --output reduced.json
# Interactive selection from URL
spec-shaver wizard --url https://api.example.com/openapi.json
# With verbose logging to see what's happening
spec-shaver wizard -v --input openapi.jsonFetch and reduce any OpenAPI schema from a URL.
import { reduceFromURL } from 'spec-shaver';
const result = await reduceFromURL('https://api.example.com/openapi.json', {
maxActions: 50,
headers: { Authorization: 'Bearer YOUR_TOKEN' },
});For more control, use the reducer class directly:
import { OpenAPIReducer } from 'spec-shaver';
import * as fs from 'fs';
// Load schema from file
const schemaContent = fs.readFileSync('openapi.json', 'utf8');
const schema = JSON.parse(schemaContent);
// Create reducer with options
const reducer = new OpenAPIReducer({
maxActions: 30,
maxSizeBytes: 1024 * 1024,
coreEntities: ['users', 'orders', 'products'],
includeExamples: false,
maxDescriptionLength: 200,
});
// Reduce the schema
const result = reducer.reduce(schema);
// Save to file
fs.writeFileSync('reduced.json', JSON.stringify(result.schema, null, 2));
// Access result information
console.log('Operations:', result.operations);
console.log('Original count:', result.originalOperationCount);
console.log('Reduced count:', result.reducedOperationCount);
console.log('Size:', result.sizeBytes);Create a .spec-shaver.json file in your project root:
{
"maxActions": 30,
"maxSizeBytes": 1048576,
"coreEntities": [
"users",
"accounts",
"organizations",
"projects",
"items",
"resources",
"events",
"messages",
"files",
"settings"
],
"includeExamples": false,
"maxDescriptionLength": 200,
"resolveRefs": false,
"output": "reduced_schema.json"
}CLI options override config file settings.
| Option | Type | Default | Description |
|---|---|---|---|
maxActions |
number |
30 |
Maximum number of operations to include |
maxSizeBytes |
number |
1048576 (1MB) |
Maximum schema size in bytes |
coreEntities |
string[] |
See below | Entities to prioritize |
includeExamples |
boolean |
false |
Whether to include example fields |
maxDescriptionLength |
number |
200 |
Maximum length for descriptions |
resolveRefs |
boolean |
false |
Resolve all $ref references by inlining them |
methodFilter |
string[] |
undefined |
Filter operations by HTTP methods |
[
'users',
'accounts',
'organizations',
'projects',
'items',
'resources',
'events',
'messages',
'files',
'settings',
]Operations are scored based on:
- Entity Importance (100 points): Paths containing core entities
- HTTP Method (20-50 points):
- GET: 50 points
- POST: 40 points
- PATCH/PUT: 30 points
- DELETE: 20 points
- Endpoint Type (10-15 points):
- Collection endpoints (e.g.,
/users): 15 points - Single resource endpoints (e.g.,
/users/{id}): 10 points
- Collection endpoints (e.g.,
- Documentation Quality (5 points): Operations with clear summaries
The reducer automatically includes all referenced schemas from the components/schemas section by:
- Scanning all selected operations for
$refreferences - Recursively resolving nested schema references
- Including only the schemas that are actually used
If the reduced schema exceeds the size limit, the reducer applies optimizations in order:
- Remove
exampleandexamplesfields from component schemas - Remove examples from path operations
- Truncate descriptions longer than
maxDescriptionLength
interface ReducerResult {
schema: OpenAPISchema; // The reduced OpenAPI schema
originalOperationCount: number; // Number of operations in original schema
reducedOperationCount: number; // Number of operations in reduced schema
sizeBytes: number; // Size of reduced schema in bytes
operations: Array<{ // List of included operations
method: string;
path: string;
summary?: string;
}>;
}const reducer = new OpenAPIReducer({
maxActions: 20,
coreEntities: ['workspaces', 'members', 'projects'],
});const reducer = new OpenAPIReducer({
maxActions: 50,
maxSizeBytes: 2 * 1024 * 1024, // 2MB
includeExamples: true,
});import { OpenAPIReducer } from 'spec-shaver';
import * as fs from 'fs';
const schemaContent = fs.readFileSync('schema.json', 'utf8');
const schema = JSON.parse(schemaContent);
const reducer = new OpenAPIReducer({ maxActions: 25 });
const result = reducer.reduce(schema);
fs.writeFileSync('output.json', JSON.stringify(result.schema, null, 2));MIT
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
Found a bug or have a feature request? Please open an issue.