typesafe-rpc

内容来源:README.md(说明文档) · 原始地址 · 查看安装指南

原始内容

TypeSafe RPC

NPM Version License: MIT

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: 'john@example.com',
  };
};

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 install

Available 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.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. 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


Made with ❤️ by Nasreddine Bac Ali