Getting Started
This guide will walk you through creating your first IRPC application with TypeScript.
Understanding IRPC Modules
IRPC applications are organized around modules, which serve as containers for related RPC functions. Each module can be configured with its own transport mechanism, allowing for flexible communication patterns across different parts of your application.
You have two main architectural options:
- Create a single module to contain all your application's functions
- Create multiple modules to group functions by domain or service boundaries
Creating Your First Module
To get started with IRPC, you'll need to create at least one module:
import { createModule } from '@irpclib/irpc';
export const irpc = createModule({
name: 'math',
version: '1.0.0'
});The createModule function accepts a configuration object with:
name: A unique identifier for your moduleversion: The version of your module (useful for API management)
Defining RPC Functions
Once you have a module, you can define RPC functions as stubs. These act as clients that will either execute locally (on the server) or remotely (on the client).
First, define your function types:
// Define the function types
type AddFunction = (a: number, b: number) => Promise<number>;
type MultiplyFunction = (a: number, b: number) => Promise<number>;Then, create the function stubs using your module:
// Define functions with explicit types
export const add = irpc<AddFunction>({
name: 'add',
description: 'Adds two numbers together'
});
export const multiply = irpc<MultiplyFunction>({
name: 'multiply'
});Setting Up Transport
Each module requires a transport mechanism to communicate between client and server. The transport handles the actual network communication.
import { createModule } from '@irpclib/irpc';
import { HTTPTransport } from '@irpclib/http';
// Create module
export const mathIrpc = createModule({
name: 'math',
version: '1.0.0'
});
// Configure transport
export const mathTransport = new HTTPTransport(
{
baseURL: 'http://localhost:3000',
endpoint: mathIrpc.endpoint,
headers: {
'Content-Type': 'application/json',
},
},
mathIrpc
);Implementing Server-Side Handlers
On the server side, you need to implement the actual functionality for your RPC functions:
mathIrpc.construct(add, async (a: number, b: number) => {
return a + b;
});
mathIrpc.construct(multiply, async (a: number, b: number) => {
return a * b;
});Setting Up the Server
Configure your server to handle IRPC requests through the transport:
import { setContextProvider } from '@irpclib/irpc';
import { AsyncLocalStorage } from 'async_hooks';
import { mathIrpc, mathTransport } from '../irpc/math';
// Set up context provider
setContextProvider(new AsyncLocalStorage());
// For Bun:
Bun.serve({
routes: {
[mathTransport.endpoint]: {
GET: () => {
return new Response('Ok!');
},
POST: (req) => mathTransport.respond(req),
}
},
});Making Client-Side Calls
On the client side, you can use your defined functions as if they were local:
import { add, multiply } from '../irpc/math';
// Make RPC calls
const sum = await add(2, 3);
console.log(sum); // 5
const product = await multiply(4, 5);
console.log(product); // 20Complete Example
Here's a complete example showing the proper structure:
irpc/math.ts:
import { createModule } from '@irpclib/irpc';
import { HTTPTransport } from '@irpclib/http';
// Define function types
type AddFunction = (a: number, b: number) => Promise<number>;
type MultiplyFunction = (a: number, b: number) => Promise<number>;
// Create module
export const mathIrpc = createModule({
name: 'math',
version: '1.0.0'
});
// Define functions
export const add = mathIrpc<AddFunction>({
name: 'add'
});
export const multiply = mathIrpc<MultiplyFunction>({
name: 'multiply'
});
// Configure transport
export const mathTransport = new HTTPTransport(
{
baseURL: 'http://localhost:3000',
endpoint: mathIrpc.endpoint,
headers: {
'Content-Type': 'application/json',
},
},
mathIrpc
);server/math.ts:
import { mathIrpc } from '../irpc/math';
// Implement handlers
mathIrpc.construct(add, async (a: number, b: number) => {
console.log(`Adding ${a} + ${b}`);
return a + b;
});
mathIrpc.construct(multiply, async (a: number, b: number) => {
console.log(`Multiplying ${a} * ${b}`);
return a * b;
});server/index.ts:
import { setContextProvider } from '@irpclib/irpc';
import { AsyncLocalStorage } from 'async_hooks';
import { mathIrpc, mathTransport } from '../irpc/math';
// Set up context provider
setContextProvider(new AsyncLocalStorage());
// For Bun:
Bun.serve({
routes: {
[mathTransport.endpoint]: {
GET: () => {
return new Response('Ok!');
},
POST: (req) => mathTransport.respond(req),
}
},
});app/App.tsx:
import { add, multiply } from '../irpc/math';
export default function App() {
const handleCalculate = async () => {
const sum = await add(2, 3);
console.log(`Sum: ${sum}`);
const multiplied = await multiply(4, 5);
console.log(`Product: ${multiplied}`);
};
return (
<div>
<button onClick={handleCalculate}>Calculate</button>
</div>
);
}