The Routing system provides composable route definitions with pattern matching, middleware, layouts, and type-safe link generation for both server and client environments.
Defines a single route with pattern matching and handler.
/**
* Defines a route with pattern matching
* @param path - URL pattern (supports parameters like "/users/:id")
* @param handler - Route handler function or React component
* @returns Route definition
*/
function route<Path, T>(
path: Path,
handler: RouteHandler<T> | MethodHandlers<T>
): RouteDefinition<NormalizePath<Path>, T>;
type NormalizePath<Path> = Path;
type RouteHandler<T> =
| React.ComponentType
| ((context?: T) => Response | React.ReactElement | Promise<Response | React.ReactElement>)
| MethodHandlers<T>;
interface MethodHandlers<T> {
GET?: (context?: T) => Response | React.ReactElement | Promise<Response | React.ReactElement>;
POST?: (context?: T) => Response | Promise<Response>;
PUT?: (context?: T) => Response | Promise<Response>;
PATCH?: (context?: T) => Response | Promise<Response>;
DELETE?: (context?: T) => Response | Promise<Response>;
HEAD?: (context?: T) => Response | Promise<Response>;
OPTIONS?: (context?: T) => Response | Promise<Response>;
}
interface RouteDefinition<Path, T> {
path: Path;
handler: RouteHandler<T>;
}Usage Examples:
import { route } from 'rwsdk/router';
// Simple component route
route('/', HomePage);
// Function handler returning Response
route('/api/hello', () => new Response('Hello, World!'));
// Async handler with JSX
route('/users/:id', async () => {
const user = await getUser();
return <UserProfile user={user} />;
});
// HTTP method-specific handlers
route('/api/users', {
GET: async () => {
const users = await getUsers();
return Response.json(users);
},
POST: async () => {
const user = await createUser();
return Response.json(user, { status: 201 });
},
});Defines the root route (equivalent to route('/', handler)).
/**
* Defines the root route
* @param handler - Route handler
* @returns Route definition
*/
function index<T>(handler: RouteHandler<T>): RouteDefinition<"/", T>;Defines multiple routes at once.
/**
* Defines an array of routes
* @param routes - Array of route definitions
* @returns Object with routes array and handle function
*/
function defineRoutes<T>(routes: readonly Route<T>[]): {
routes: Route<T>[];
handle: (request: Request, env: any, ctx: ExecutionContext) => Response | Promise<Response>;
};
type Route<T> = RouteDefinition<any, T> | Route<T>[];Adds a common prefix to a group of routes.
/**
* Prefixes a group of routes
* @param prefixPath - Common path prefix (e.g., "/api")
* @param routes - Routes to prefix
* @returns Prefixed route group
*/
function prefix<Prefix, T, Routes>(
prefixPath: Prefix,
routes: Routes
): PrefixedRouteArray<Prefix, Routes>;
type PrefixedRouteArray<Prefix, Routes> = Route<any>[];Usage Example:
import { prefix, route } from 'rwsdk/router';
const apiRoutes = prefix('/api', [
route('/users', getUsers),
route('/posts', getPosts),
]);
// Results in: /api/users, /api/postsWraps routes with a layout component that receives children and context.
/**
* Wraps routes with a layout component
* @param LayoutComponent - Layout component receiving children and context
* @param routes - Routes to wrap
* @returns Wrapped route group
*/
function layout<T, Routes>(
LayoutComponent: React.ComponentType<LayoutProps<T>>,
routes: Routes
): Route<T>;
interface LayoutProps<T = any> {
children: React.ReactNode;
context?: T;
}Usage Example:
import { layout, route } from 'rwsdk/router';
function AppLayout({ children }) {
return (
<div>
<nav>Navigation</nav>
<main>{children}</main>
</div>
);
}
const routes = layout(AppLayout, [
route('/', HomePage),
route('/about', AboutPage),
]);Wraps routes with a Document component for HTML structure.
/**
* Wraps routes with a Document component
* @param Document - Document component for HTML structure
* @param routes - Routes to wrap
* @param options - Optional rendering options
* @returns Wrapped route group
*/
function render<T, Routes>(
Document: React.ComponentType<DocumentProps<T>>,
routes: Routes,
options?: RenderOptions
): RenderedRoutes<T, Routes>;
interface DocumentProps<T = any> {
children: React.ReactNode;
context?: T;
}
interface RenderOptions {
/** Whether to include RSC payload (default: true) */
rscPayload?: boolean;
/** Whether to use SSR (default: true) */
ssr?: boolean;
}
type RenderedRoutes<T, Routes> = Route<T>;Usage Example:
import { render, route } from 'rwsdk/router';
function Document({ children }) {
return (
<html>
<head>
<title>My App</title>
</head>
<body>{children}</body>
</html>
);
}
const app = render(Document, [
route('/', HomePage),
route('/about', AboutPage),
]);Matches route patterns against request paths.
/**
* Matches a route pattern against a request path
* @param routePath - Route pattern (e.g., "/users/:id")
* @param requestPath - Actual request path (e.g., "/users/123")
* @returns Match result with params or null
*/
function matchPath<T>(
routePath: string,
requestPath: string
): T["params"] | null;Utility functions for route handlers.
/**
* Checks if a value is a client reference
* @param value - Value to check
* @returns True if value is a client reference
*/
function isClientReference(value: any): boolean;Creates type-safe link builders from route definitions.
/**
* Defines a type-safe link builder from routes
* @returns Link builder function
*/
function defineLinks<App>(): AppLink<App>;
function defineLinks<T>(routes: T): LinkFunction<T[number]>;
/**
* Creates a link function for an app
* @returns Link generation function
*/
function linkFor<App>(): AppLink<App>;
/**
* Creates links from app definition
* @param app - Optional app definition
* @returns Link builder
*/
function createLinks<App>(app?: App): AppLink<App>;
type AppLink<App> = {
[K in AppRoutePaths<App>]: (params?: Record<string, string>) => string;
};
type AppRoutePaths<App> = string;
type LinkFunction<Paths> = (path: Paths, params?: Record<string, string>) => string;Usage Example:
import { defineApp, route, defineLinks } from 'rwsdk/router';
const app = defineApp([
route('/', HomePage),
route('/users/:id', UserPage),
route('/posts/:slug', PostPage),
]);
const links = createLinks(app);
// Type-safe link generation
const userLink = links['/users/:id']({ id: '123' });
// Result: "/users/123"
const postLink = links['/posts/:slug']({ slug: 'hello-world' });
// Result: "/posts/hello-world"Route patterns support parameter extraction:
/about, /api/users/users/:id, /posts/:slug/blog/:year/:month/:slug/files/*Routes can be composed and nested in various ways:
import { defineApp, route, prefix, layout, render } from 'rwsdk/router';
function RootLayout({ children }) {
return <div className="root">{children}</div>;
}
function AdminLayout({ children }) {
return (
<div className="admin">
<aside>Admin Menu</aside>
<main>{children}</main>
</div>
);
}
function Document({ children }) {
return (
<html>
<body>{children}</body>
</html>
);
}
const app = defineApp([
render(Document, [
layout(RootLayout, [
route('/', HomePage),
route('/about', AboutPage),
prefix('/admin', [
layout(AdminLayout, [
route('/', AdminDashboard),
route('/users', AdminUsers),
]),
]),
]),
]),
]);On the client, use a subset of routing functions:
// Client-side routing (from rwsdk/router on client)
function defineLinks(routes?: any): LinkBuilder;
function linkFor<App>(): (path: string, params?: Record<string, string>) => string;type MethodVerb = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
type RouteMiddleware<T> = (
handler: RouteHandler<T>,
context: T
) => RouteHandler<T>;