Automatically Generate Type-Safe API Functions for Your RESTful APIs
AxiosFlow is a powerful TypeScript library that simplifies API consumption by automatically generating type-safe API functions for your RESTful APIs. It eliminates boilerplate code, ensures compile-time type safety, and works seamlessly with Express.js and Axios.
Building type-safe APIs can be time-consuming and error-prone. AxiosFlow solves this by:
- Automating API Function Generation: No more writing repetitive API call functions.
- Ensuring Compile-Time Type Safety: Catch errors before runtime with TypeScript.
- Reducing Boilerplate Code: Focus on building features, not writing API glue code.
- Seamless Integration: Works with your existing Express.js backend and Axios client.
- Robust Error Prevention: Ensures type-safe API calls.
- Compile-Time Validation: Catches type mismatches before runtime.
- Enhanced Code Quality: Reduces potential errors in API interactions.
- Automatic Function Creation: Generates fully typed API client functions.
- Eliminates Manual Type Definitions: Dramatically reduces boilerplate code.
- Compile-Time Type Safety: Guarantees type consistency across API interactions.
- Backend to Frontend Type Mapping: Seamless type propagation.
- Catches Potential Type Mismatches: Ensures consistency during development.
- Automatic API Function Generation: Generates type-safe API functions with minimal configuration.
- Dynamic URL Parameter Support: Easily handle dynamic routes like
/users/:id
. - Minimal Configuration Required: Works out of the box with Express.js and Axios.
Feature/Tool | AxiosFlow | tRPC | OpenAPI (Swagger) | GraphQL Code Generator | Zodios | Manual Typing |
---|---|---|---|---|---|---|
Type Safety | Compile-time | Compile-time | Runtime | Compile-time | Runtime (Zod) | Manual |
Ease of Use | Easy (Express.js + Axios) | Moderate (tRPC setup) | Moderate (YAML/JSON) | Moderate (GraphQL) | Moderate (Zod schemas) | Manual |
Flexibility | High (framework-agnostic) | Low (tRPC-specific) | High (RESTful APIs) | Low (GraphQL-only) | High (Zod integration) | High |
Boilerplate Code | Minimal | Minimal | Moderate | Minimal | Moderate | High |
AxiosFlow is the simplest and most flexible solution for adding type safety to RESTful APIs without requiring a new framework or maintaining a separate schema.
Check out the examples
folder for complete implementation samples:
- Client: A React/TypeScript frontend using AxiosFlow.
- Server: An Express.js backend with AxiosFlow integration.
Check out the live examples on CodeSandbox to see AxiosFlow in action:
npm install express@4.21.2 cors dotenv axiosflow-api
npm install -D typescript @types/express @types/cors ts-node
import { Request, Response } from 'express';
// Interfaces for type safety
export class UserRequest {
name: string | undefined;
}
export class User {
id: number | undefined;
name: string | undefined;
}
export class UserController {
private users: User[] = [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Doe' },
];
getUsers(req: Request, res: Response): Response {
return res.status(200).json({
status: 'success',
data: this.users,
});
}
getUserById(req: Request, res: Response): Response {
const userId = parseInt(req.params.id);
const user = this.users.find((u) => u.id === userId);
if (!user) {
return res.status(404).json({
status: 'error',
message: 'User not found',
});
}
return res.status(200).json({
status: 'success',
data: user,
});
}
createUser(req: Request, res: Response): Response {
const { name } = req.body as UserRequest;
if (!name) {
return res.status(400).json({
status: 'error',
message: 'Name is required',
});
}
const newUser = {
id: this.users.length + 1,
name
};
this.users.push(newUser);
return res.status(201).json({
status: 'success',
data: newUser,
});
}
}
import { registerRoute, typeRef } from 'axiosflow-api';
import { UserController, UserRequest, User } from '../controllers/userController';
// Create an instance of the controller
const userController = new UserController();
// Define routes and register them dynamically
export function registerUserRoutes() {
registerRoute(
userController,
'GET',
'/users',
null,
typeRef<User>('User', { id: 'number', name: 'string' }),
[],
'getUsers'
);
registerRoute(
userController,
'GET',
'/users/:id',
null,
typeRef<User>('User', { id: 'number', name: 'string' }),
[],
'getUserById'
);
registerRoute(
userController,
'POST',
'/users',
typeRef<UserRequest>('UserRequest', { name: 'string' }),
typeRef<User>('User', { id: 'number', name: 'string' }),
[],
'createUser'
);
}
// Export the controller instance for use in the router
export const controllerInstances = {
UserController: userController,
};
import { Router } from 'express';
import { createRoutes } from 'axiosflow-api';
import { registerUserRoutes, controllerInstances } from './userRoutes';
const router = Router();
// Register user routes
registerUserRoutes();
// Dynamically create routes based on registered metadata
createRoutes(router, controllerInstances);
export default router;
import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';
import router from './routes/router';
import { exportRoutesForSchema } from 'axiosflow-api';
dotenv.config();
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(cors());
app.use(express.json());
// Routes
app.use('/api', router);
// Route to export API schema
app.get('/axiosflow', (req, res) => {
const routes = exportRoutesForSchema();
res.json(routes);
});
// Global error handler
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
console.error(err.stack);
res.status(500).json({
message: 'Something went wrong',
error: process.env.NODE_ENV !== 'production' ? err : {}
});
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
import { Request, Response, NextFunction } from 'express';
import { registerRoute, typeRef } from 'axiosflow-api';
// CSRF middleware
const csrfProtection: RequestHandler = csrf({ cookie: true });
// logger middleware
const logger: RequestHandler = (req, res, next) => {
console.log(`${req.method} ${req.path}`);
next();
};
export function registerUserRoutes() {
// GET Users - Simple logging middleware
registerRoute(
userController,
'GET',
'/users',
null,
typeRef<User>('User', { id: 'number', name: 'string' }),
[csrfProtection,logger],
'getUsers'
);
// GET User by ID - Authentication and logging
registerRoute(
userController,
'GET',
'/users/:id',
null,
typeRef<User>('User', { id: 'number', name: 'string' }),
[csrfProtection, logger],
'getUserById'
);
}
Node.js (v16+) TypeScript Axios
npm install -g axiosflow
pnpm add axiosflow
axiosflow --help
# Basic generation
axiosflow generate
# With specific options
axiosflow generate -b http://localhost:3000 -o ./src/services
src/services/
├── apiFunctions.ts # Generated API functions
├── apiConfig.ts # API endpoint configurations
├── types.ts # Type definitions
└── api-schema.json # API schema documentation
import { get_users } from './services/apiFunctions';
async function UserList() {
try {
const users = await get_users();
// Handle users
} catch (error) {
// Handle error
}
}
import { post_users } from './services/apiFunctions';
async function createUser(name: string) {
try {
const newUser = await post_users({ name });
// Handle new user
} catch (error) {
// Handle error
}
}
or in components :
import React, { useEffect, useState } from 'react';
import { get_users, post_users, get_users_id } from '../services/apiFunctions';
import { User, UserRequest } from '../services/types';
const UserComponent: React.FC = () => {
const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
// Fetch the list of users from the API on component mount
useEffect(() => {
const fetchUsers = async () => {
try {
setLoading(true);
setError(null);
console.log('Attempting to fetch users...');
const userList = await get_users();
console.log('Fetched Users:', userList);
if (userList.length > 0) {
setUsers(userList);
} else {
setError('No users found');
}
} catch (err) {
console.error('Fetch Users Error:', err);
const errorMessage = err instanceof Error
? err.message
: 'An unexpected error occurred';
setError(errorMessage);
} finally {
setLoading(false);
}
};
fetchUsers();
}, []);
return (
<div>
<h1>Users Lists</h1>
</div>
);
};