TypeScript/JavaScript client for the Katana Manufacturing ERP API with automatic resilience features.
- Automatic Retries - Exponential backoff with configurable retry limits
- Rate Limiting Awareness - Respects 429 responses and
Retry-Afterheaders - Auto-Pagination - Automatically collects all pages for GET requests
- Type Safety - Full TypeScript types generated from OpenAPI spec
- Browser & Node.js - Works in both environments
- Tree-Shakeable - Only import what you need
npm install katana-openapi-client
# or
pnpm add katana-openapi-client
# or
yarn add katana-openapi-clientimport { KatanaClient } from 'katana-openapi-client';
// Create client with API key
const client = await KatanaClient.create({
apiKey: 'your-api-key',
});
// Or use environment variable (KATANA_API_KEY)
const client = await KatanaClient.create();
// Or provide API key directly
const client = KatanaClient.withApiKey('your-api-key');
// Make requests - auto-pagination collects all pages
const response = await client.get('/products');
const { data } = await response.json();
console.log(`Found ${data.length} products`);If you only need TypeScript types without any runtime code:
import type { Product, SalesOrder, Variant } from 'katana-openapi-client/types';
function processProduct(product: Product) {
// ...
}const client = await KatanaClient.create({
// API key (or set KATANA_API_KEY env var)
apiKey: 'your-api-key',
// Custom base URL (default: https://api.katanamrp.com/v1)
baseUrl: 'https://api.katanamrp.com/v1',
// Retry configuration
retry: {
maxRetries: 5, // Default: 5
backoffFactor: 1.0, // Default: 1.0 (1s, 2s, 4s, 8s, 16s)
respectRetryAfter: true, // Default: true
},
// Pagination configuration
pagination: {
maxPages: 100, // Default: 100
maxItems: undefined, // Limit total items (optional)
defaultPageSize: 250, // Default: 250
},
// Disable auto-pagination globally
autoPagination: false,
});The client implements the same retry strategy as the Python client:
| Status Code | GET/PUT/DELETE | POST/PATCH |
|---|---|---|
| 429 (Rate Limit) | Retry | Retry |
| 502, 503, 504 | Retry | No Retry |
| Other 4xx | No Retry | No Retry |
| Network Error | Retry | Retry |
Key behavior: POST and PATCH requests are retried for rate limiting (429) because rate limits are transient and don't indicate idempotency issues.
Auto-pagination is ON by default for all GET requests:
// Collects all pages automatically
const response = await client.get('/products');
const { data, pagination } = await response.json();
console.log(`Collected ${pagination.total_items} items from ${pagination.collected_pages} pages`);To disable auto-pagination:
// Explicit page parameter disables auto-pagination
const response = await client.get('/products', { page: 2, limit: 50 });
// Or globally via configuration
const client = await KatanaClient.create({
autoPagination: false,
});The client returns standard Response objects. Use parseError for typed error
handling:
import {
KatanaClient,
parseError,
AuthenticationError,
RateLimitError,
ValidationError,
} from 'katana-openapi-client';
const response = await client.post('/products', { name: 'Widget' });
if (!response.ok) {
const body = await response.json();
const error = parseError(response, body);
if (error instanceof AuthenticationError) {
console.error('Invalid API key');
} else if (error instanceof RateLimitError) {
console.error(`Rate limited. Retry after ${error.retryAfter}s`);
} else if (error instanceof ValidationError) {
console.error('Validation errors:', error.details);
// [{ field: 'name', message: 'Required', code: 'missing' }]
} else {
console.error(`Error ${error.statusCode}: ${error.message}`);
}
}Available error classes:
AuthenticationError(401)RateLimitError(429) - includesretryAftersecondsValidationError(422) - includesdetailsarrayServerError(5xx)NetworkError- connection failuresKatanaError- base class for all errors
// GET (auto-paginated by default)
const products = await client.get('/products');
const productById = await client.get('/products/123');
const filtered = await client.get('/products', { category: 'widgets' });
// POST
const created = await client.post('/products', {
name: 'New Product',
sku: 'PROD-001',
});
// PUT
const updated = await client.put('/products/123', {
name: 'Updated Product',
});
// PATCH
const patched = await client.patch('/products/123', {
name: 'Patched Name',
});
// DELETE
const deleted = await client.delete('/products/123');The package exports generated SDK functions with full TypeScript types. You can use them with the resilient client:
import { KatanaClient, getAllProducts, createProduct } from 'katana-openapi-client';
// Create the resilient client
const katana = await KatanaClient.create();
// Use SDK functions with the resilient client
const { data, error } = await getAllProducts({ client: katana.sdk });
if (data) {
console.log(`Found ${data.length} products`);
}
// Or use the config shorthand
const result = await getAllProducts(katana.getConfig());The SDK functions provide:
- Full TypeScript types for all request/response bodies
- Auto-completion for query parameters
- Type-safe error handling
KATANA_API_KEY- API key for authenticationKATANA_BASE_URL- Override the base URL (optional)
Node.js 20.6+ (recommended):
node --env-file=.env your-script.jsNode.js 18-20.5 (use dotenv):
npm install dotenvimport 'dotenv/config';
import { KatanaClient } from 'katana-openapi-client';
const client = KatanaClient.withApiKey(process.env.KATANA_API_KEY!);Note: This library supports Node.js 18+ but does not bundle dotenv. If you need .env file loading on Node.js < 20.6, install dotenv as a direct dependency in your project.
For more detailed documentation:
- Client Guide - Comprehensive usage guide
- Cookbook - Common patterns and recipes
- Testing Guide - Testing strategy and patterns
- Architecture Decisions - Design decisions and rationale
MIT