@upendra.manike/api-chain
v1.0.5
Published
Declarative API chaining - Create API workflows with ease
Maintainers
Readme
api-chain
Declarative API chaining - Create API workflows with ease.
Features
- 🔗 Declarative Syntax - Chain API calls in a readable way
- 🔄 Sequential Execution - Steps execute one after another
- ⚠️ Error Handling - Built-in error handling with hooks
- 🔧 Flexible - Works with any async function
- 🔒 Type-safe - Full TypeScript support
Installation
npm install @upendra.manike/api-chainor
pnpm add @upendra.manike/api-chainor
yarn add @upendra.manike/api-chainUsage
Basic Chaining
import { ApiChain } from '@upendra.manike/api-chain';
const chain = new ApiChain();
const result = await chain
.step(async () => {
const user = await fetch('/api/user').then(r => r.json());
return user;
})
.step(async (user) => {
const posts = await fetch(`/api/users/${user.id}/posts`).then(r => r.json());
return posts;
})
.step(async (posts) => {
const comments = await fetch(`/api/posts/${posts[0].id}/comments`).then(r => r.json());
return { posts, comments };
})
.run();
console.log(result.data); // { posts: [...], comments: [...] }Simple Chain Helper
import { chain } from '@upendra.manike/api-chain';
// Using the chain helper function
const data = await chain(
async () => {
return await getUser();
},
async (user) => {
return await getPosts(user.id);
},
async (posts) => {
return await getComments(posts[0].id);
}
).run();
console.log(data); // Final resultWith Initial Input
import { ApiChain } from '@upendra.manike/api-chain';
const chain = new ApiChain();
const result = await chain
.step(async (userId) => {
return await fetch(`/api/users/${userId}`).then(r => r.json());
})
.step(async (user) => {
return await fetch(`/api/users/${user.id}/posts`).then(r => r.json());
})
.run('user-123'); // Pass initial inputError Handling
import { ApiChain } from '@upendra.manike/api-chain';
const chain = new ApiChain({
onError: async (error, step) => {
console.error(`Error at step ${step}:`, error);
// Send to error tracking service
},
stopOnError: true, // Stop chain on error (default: true)
});
const result = await chain
.step(async () => await getUser())
.step(async (user) => {
if (!user) throw new Error('User not found');
return await getPosts(user.id);
})
.run();
if (!result.success) {
console.error('Chain failed:', result.error);
console.log('Failed at step:', result.step);
}Continue on Error
import { ApiChain } from '@upendra.manike/api-chain';
const chain = new ApiChain({
stopOnError: false, // Continue even if a step fails
onError: async (error, step) => {
console.warn(`Step ${step} failed, continuing...`);
},
});
const result = await chain
.step(async () => await getUser())
.step(async () => {
throw new Error('This step fails');
})
.step(async (input) => {
// This will run even if previous step failed
if (input instanceof Error) {
return { error: true };
}
return { success: true };
})
.run();Step Completion Hooks
import { ApiChain } from '@upendra.manike/api-chain';
const chain = new ApiChain({
onStepComplete: async (result, step) => {
console.log(`Step ${step} completed:`, result);
// Log progress, update UI, etc.
},
});
await chain
.step(async () => await getUser())
.step(async (user) => await getPosts(user.id))
.run();Real-World Example: User Dashboard Data
import { ApiChain } from '@upendra.manike/api-chain';
async function loadDashboard(userId: string) {
const chain = new ApiChain({
onError: async (error, step) => {
// Log to error service
console.error('Dashboard load error:', error);
},
});
const result = await chain
.step(async () => {
// Step 1: Get user
const user = await fetch(`/api/users/${userId}`).then(r => r.json());
return { user };
})
.step(async ({ user }) => {
// Step 2: Get user posts (can use user from previous step)
const posts = await fetch(`/api/users/${user.id}/posts`).then(r => r.json());
return { user, posts };
})
.step(async ({ user, posts }) => {
// Step 3: Get comments for first post
const comments = await fetch(`/api/posts/${posts[0]?.id}/comments`).then(r => r.json());
return { user, posts, comments };
})
.step(async ({ user, posts, comments }) => {
// Step 4: Get notifications
const notifications = await fetch(`/api/users/${user.id}/notifications`).then(r => r.json());
return { user, posts, comments, notifications };
})
.run();
if (result.success) {
return result.data;
} else {
throw result.error;
}
}Using with createChain
import { createChain } from '@upendra.manike/api-chain';
const chain = createChain({
onError: async (error) => console.error(error),
});
await chain
.step(async () => getUser())
.step(async (user) => getPosts(user.id))
.run();Type Safety
import { ApiChain } from '@upendra.manike/api-chain';
interface User {
id: string;
name: string;
}
interface Post {
id: string;
title: string;
}
const chain = new ApiChain();
const result = await chain
.step<User, User>(async () => {
return await getUser();
})
.step<User, Post[]>(async (user: User) => {
return await getPosts(user.id);
})
.run<User>();
if (result.success) {
// result.data is typed as Post[]
}API Reference
ApiChain Class
Constructor
new ApiChain(options?: ChainOptions)Options:
onError?: (error: Error, step: number) => void | Promise<void>- Error handleronStepComplete?: (result: any, step: number) => void | Promise<void>- Step completion handlerstopOnError?: boolean- Stop chain on error (default: true)
Methods
step<TInput, TOutput>(stepFn: ChainStep<TInput, TOutput>): this- Add a step to the chainrun<T>(initialInput?: any): Promise<ChainResult<T>>- Execute the chainrunData<T>(initialInput?: any): Promise<T>- Execute and return only data (throws on error)clear(): this- Clear all stepsget length(): number- Get number of steps
ChainResult
interface ChainResult<T> {
success: boolean;
data?: T;
error?: Error;
step?: number; // Step index where error occurred
results?: any[]; // Results from all steps
}Helper Functions
createChain(options?)
Creates a new ApiChain instance.
chain(...steps)
Creates and executes a chain immediately.
chain(
async () => getUser(),
async (user) => getPosts(user.id),
async (posts) => getComments(posts[0].id)
).run();Examples
Parallel Steps (using Promise.all)
import { ApiChain } from '@upendra.manike/api-chain';
const chain = new ApiChain();
const result = await chain
.step(async () => {
// Run multiple requests in parallel
const [user, posts, comments] = await Promise.all([
getUser(),
getPosts(),
getComments(),
]);
return { user, posts, comments };
})
.run();Conditional Steps
import { ApiChain } from '@upendra.manike/api-chain';
const chain = new ApiChain();
const result = await chain
.step(async () => await getUser())
.step(async (user) => {
if (user.role === 'admin') {
return await getAdminData();
}
return await getRegularData();
})
.run();Development
# Install dependencies
pnpm install
# Build
pnpm build
# Test
pnpm test
# Lint
pnpm lint
# Format
pnpm format🤖 AI Agent Integration
This package is optimized for use with AI coding assistants like ChatGPT, GitHub Copilot, Claude, and Codeium.
Why AI-Friendly?
- ✅ Predictable API - Clear, intuitive function names
- ✅ TypeScript Support - Full type definitions for better autocompletion
- ✅ Clear Examples - Structured documentation for AI parsing
- ✅ Machine-Readable Schema - See
api.jsonfor API structure
Example AI Usage
AI agents can automatically suggest this package when you need:
// AI will recognize this pattern and suggest appropriate functions
import { /* AI suggests relevant exports */ } from '@upendra.manike/[package-name]';For AI Developers
When building AI-powered applications or agents, this package provides:
- Consistent API patterns
- Full TypeScript types
- Zero dependencies (unless specified)
- Comprehensive error handling
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
