typesafe-rpc
v0.0.29
Published
A typesafe RPC library for Node.js, TypeScript and React.
Readme
TypeSafe RPC
A modern, type-safe RPC (Remote Procedure Call) library for Node.js, TypeScript, and React applications. Built with full TypeScript support, providing end-to-end type safety between client and server.
🚀 Features
- Full TypeScript Support: Complete type safety from server to client
- Modern Architecture: Built for modern web applications with ES modules
- Middleware Support: Extensible middleware system for authentication, logging, and more
- Performance Monitoring: Built-in hooks for performance tracking
- Error Handling: Comprehensive error handling with customizable error responses
- Abort Signal Support: Cancel requests with AbortController
- Zero Dependencies: Minimal runtime dependencies for optimal bundle size
📦 Installation
npm install typesafe-rpc
# or
yarn add typesafe-rpc
# or
pnpm add typesafe-rpc
# or
bun add typesafe-rpc🎯 Quick Start
1. Define Your API Schema
// api-schema.ts
import type { BaseContext, Handler } from 'typesafe-rpc';
type UserContext = BaseContext & {
user?: { id: string; name: string };
};
type UserParams = { id: string };
type UserResult = { id: string; name: string; email: string };
const getUserHandler: Handler<UserParams, UserContext, UserResult, {}> = async ({
params,
context,
}) => {
// Your business logic here
return {
id: params.id,
name: 'John Doe',
email: '[email protected]',
};
};
export const apiSchema = {
users: {
getById: getUserHandler,
},
} as const;2. Set Up the Server
// server.ts
import { createRpcHandler } from 'typesafe-rpc/server';
import { apiSchema } from './api-schema';
export async function handleRequest(request: Request): Promise<Response> {
const context = { request };
return createRpcHandler({
context,
operations: apiSchema,
errorHandler: (error) => {
console.error('RPC Error:', error);
return new Response(JSON.stringify({ error: 'Internal Server Error' }), {
status: 500,
headers: { 'Content-Type': 'application/json' },
});
},
hooks: {
preCall: (context) => console.log('RPC call started'),
postCall: (context, performance) => console.log(`RPC call completed in ${performance}ms`),
error: (context, performance, error) =>
console.error(`RPC call failed after ${performance}ms:`, error),
},
});
}3. Create the Client
// client.ts
import { createRpcClient } from 'typesafe-rpc/client';
import type { apiSchema } from './api-schema';
const client = createRpcClient<typeof apiSchema>('/api/rpc');
// Usage with full type safety
const user = await client.users.getById({ id: '123' });
console.log(user.name); // TypeScript knows this exists!4. Use in React
// React component
import { useState, useEffect } from 'react';
import { client } from './client';
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const controller = new AbortController();
client.users.getById({ id: userId }, controller.signal)
.then(setUser)
.catch(console.error)
.finally(() => setLoading(false));
return () => controller.abort();
}, [userId]);
if (loading) return <div>Loading...</div>;
if (!user) return <div>User not found</div>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}🔧 API Reference
Core Types
BaseContext
type BaseContext = {
request: Request;
};Handler<Params, Context, Result, ExtraParams>
type Handler<Params, Context extends BaseContext, Result, ExtraParams> = (
args: Args<Params, Context, ExtraParams>,
) => Promise<Result>;RpcSchema
type RpcSchema = {
[entity: string]: {
[operation: string]: Handler<any, any, any, any>;
};
};Server API
createRpcHandler<T, Context>
Creates an RPC handler for processing requests.
function createRpcHandler<T extends RpcSchema, Context extends BaseContext>({
context,
operations,
errorHandler?,
hooks?,
}: {
context: Context;
operations: T;
errorHandler?: (error: any) => Response;
hooks?: {
preCall?: (context: Context) => void;
postCall?: (context: Context, performance: number) => void;
error?: (context: Context, performance: number, error: any) => void;
};
}): Promise<Response>Client API
createRpcClient<T>(endpoint)
Creates a type-safe RPC client.
function createRpcClient<T extends RpcSchema>(endpoint: string): RpcClient<T>;The returned client provides a proxy that matches your schema structure with full type safety.
Middleware System
import type { Middleware } from 'typesafe-rpc';
// Authentication middleware
const authMiddleware: Middleware<any, BaseContext, {}, { user: { id: string } }> = async ({
context,
}) => {
const token = context.request.headers.get('Authorization');
if (!token) throw new Response('Unauthorized', { status: 401 });
// Verify token and return user info
return { user: { id: 'user-123' } };
};
// Usage in handler
const protectedHandler: Handler<
UserParams,
BaseContext,
UserResult,
{ user: { id: string } }
> = async ({ params, context, extraParams }) => {
// extraParams.user is now available with full type safety
return {
/* ... */
};
};🛠️ Development
Prerequisites
- Node.js 18+
- Bun 1.3.5+
Setup
git clone https://github.com/bacali95/typesafe-rpc.git
cd typesafe-rpc
bun installAvailable Scripts
# Build the library
bun run build
# Run tests
bun run test
# Lint code
bun run lint
# Format code
bun run prettier:fix
# Check code formatting
bun run prettier:check🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built with Nx for monorepo management
- TypeScript-first design for maximum developer experience
- Modern web standards with ES modules and Fetch API
📞 Support
- 📧 Email: [email protected]
- 🐛 Issues: GitHub Issues
- 📖 Documentation: GitHub Pages
Made with ❤️ by Nasreddine Bac Ali
