Routes API
Routes in Flow-Like map URL paths to pages or events. This guide covers the technical implementation of the routing system.
Route Architecture
Section titled “Route Architecture”┌─────────────────────────────────────────────────────────────┐│ Request Flow │├─────────────────────────────────────────────────────────────┤│ ││ User Request ││ │ ││ ▼ ││ ┌─────────────────┐ ││ │ Route Matcher │ ← Priority & Path Matching ││ └────────┬────────┘ ││ │ ││ ▼ ││ ┌─────────────────────────────────────────────┐ ││ │ Target Resolution │ ││ ├─────────────────────┬───────────────────────┤ ││ │ targetType: page │ targetType: event │ ││ │ │ │ │ │ ││ │ ▼ │ ▼ │ ││ │ ┌─────────┐ │ ┌─────────┐ │ ││ │ │ Page │ │ │ Event │ │ ││ │ │ Render │ │ │ Handler │ │ ││ │ └─────────┘ │ └─────────┘ │ ││ └─────────────────────┴───────────────────────┘ ││ │└─────────────────────────────────────────────────────────────┘Route Interface
Section titled “Route Interface”IAppRoute
Section titled “IAppRoute”The full route object stored in the system:
interface IAppRoute { id: string; // Unique route identifier appId: string; // Parent app ID path: string; // URL path (e.g., "/dashboard") targetType: RouteTargetType; // "page" | "event" pageId?: string; // Target page ID (if targetType is "page") boardId?: string; // Associated board/flow ID pageVersion?: Version; // Specific page version to use eventId?: string; // Target event ID (if targetType is "event") isDefault: boolean; // Is this the default/home route priority: number; // Route matching priority (higher = first) label?: string; // Display label for navigation icon?: string; // Icon identifier for navigation createdAt: string; // ISO timestamp updatedAt: string; // ISO timestamp}RouteTargetType
Section titled “RouteTargetType”type RouteTargetType = "page" | "event";| Value | Description |
|---|---|
"page" | Route renders an A2UI page |
"event" | Route triggers a flow event |
Route State API
Section titled “Route State API”Interface
Section titled “Interface”interface IAppRouteState { // Query routes getRoutes(appId: string): Promise<IAppRoute[]>; getRouteByPath(appId: string, path: string): Promise<IAppRoute | null>; getDefaultRoute(appId: string): Promise<IAppRoute | null>;
// Mutate routes createRoute(appId: string, route: CreateAppRoute): Promise<IAppRoute>; updateRoute(appId: string, routeId: string, route: UpdateAppRoute): Promise<IAppRoute>; deleteRoute(appId: string, routeId: string): Promise<void>;}CreateAppRoute
Section titled “CreateAppRoute”When creating a route, you don’t need to specify id, appId, createdAt, or updatedAt:
interface CreateAppRoute { path: string; // Required: URL path targetType: RouteTargetType; // Required: "page" or "event" pageId?: string; // Required if targetType is "page" boardId?: string; // Optional: associated board pageVersion?: Version; // Optional: pin to specific version eventId?: string; // Required if targetType is "event" isDefault?: boolean; // Default: false priority?: number; // Default: 0 label?: string; // Optional: display label icon?: string; // Optional: icon name}UpdateAppRoute
Section titled “UpdateAppRoute”All fields are optional when updating:
interface UpdateAppRoute { path?: string; targetType?: RouteTargetType; pageId?: string; boardId?: string; pageVersion?: Version; eventId?: string; isDefault?: boolean; priority?: number; label?: string; icon?: string;}Usage Examples
Section titled “Usage Examples”Get All Routes
Section titled “Get All Routes”const routes = await backend.routeState.getRoutes(appId);console.log(`App has ${routes.length} routes`);Get Route by Path
Section titled “Get Route by Path”const route = await backend.routeState.getRouteByPath(appId, "/dashboard");if (route) { console.log(`Dashboard route points to ${route.targetType}: ${route.pageId || route.eventId}`);}Get Default Route
Section titled “Get Default Route”const homeRoute = await backend.routeState.getDefaultRoute(appId);if (homeRoute) { // Redirect to home page navigateTo(homeRoute.path);}Create a Page Route
Section titled “Create a Page Route”const newRoute = await backend.routeState.createRoute(appId, { path: "/reports", targetType: "page", pageId: "page_abc123", boardId: "board_xyz789", label: "Reports", icon: "chart",});Create an Event Route
Section titled “Create an Event Route”const webhookRoute = await backend.routeState.createRoute(appId, { path: "/api/webhook", targetType: "event", eventId: "event_webhook_handler", priority: 10, // Higher priority for API routes});Update a Route
Section titled “Update a Route”// Make a route the defaultawait backend.routeState.updateRoute(appId, routeId, { isDefault: true,});
// Change route targetawait backend.routeState.updateRoute(appId, routeId, { targetType: "page", pageId: "new_page_id", eventId: undefined, // Clear the event ID});Delete a Route
Section titled “Delete a Route”await backend.routeState.deleteRoute(appId, routeId);Route Resolution
Section titled “Route Resolution”Path Matching
Section titled “Path Matching”Routes are matched in this order:
- Exact match - Path matches exactly
- Priority order - Higher
priorityvalue checked first - Creation order - Earlier routes checked first
Default Route
Section titled “Default Route”The default route (isDefault: true) is used when:
- User navigates to the app root (
/) - No other route matches the requested path
- Only one route can be default per app
Version Pinning
Section titled “Version Pinning”For page routes, you can pin to a specific page version:
{ path: "/stable-dashboard", targetType: "page", pageId: "dashboard", pageVersion: { major: 1, minor: 0, patch: 0, type: "stable" }}Version types:
| Type | Description |
|---|---|
"draft" | Work in progress |
"preview" | Testing version |
"stable" | Production-ready |
"archived" | Deprecated |
Navigation
Section titled “Navigation”From Flows
Section titled “From Flows”Use navigation nodes to redirect users:
[Navigate Node]├── Route Path: "/success"└── Mode: "replace" | "push"From Components
Section titled “From Components”A2UI components can trigger navigation:
{ "type": "Button", "props": { "label": "Go to Reports" }, "actions": { "onClick": { "type": "navigate", "path": "/reports" } }}Programmatic Navigation
Section titled “Programmatic Navigation”From frontend code:
// Using the routerrouter.push(`/use?app=${appId}&route=/dashboard`);
// With route stateconst route = await backend.routeState.getRouteByPath(appId, targetPath);if (route) { // Handle the route target}Error Handling
Section titled “Error Handling”Route Not Found
Section titled “Route Not Found”When no route matches:
const route = await backend.routeState.getRouteByPath(appId, requestedPath);if (!route) { // Fall back to default route const defaultRoute = await backend.routeState.getDefaultRoute(appId); if (!defaultRoute) { // Show 404 or app landing }}Duplicate Path Prevention
Section titled “Duplicate Path Prevention”Creating a route with a duplicate path will fail:
try { await backend.routeState.createRoute(appId, { path: "/existing-path", // Already exists targetType: "page", pageId: "some-page", });} catch (error) { // Handle duplicate path error}Best Practices
Section titled “Best Practices”API Routes
Section titled “API Routes”For event-based API routes:
- Use
/api/prefix for clarity - Set higher priority to avoid page route conflicts
- Consider authentication requirements
{ path: "/api/data", targetType: "event", eventId: "data_handler", priority: 100, // High priority}Page Routes
Section titled “Page Routes”For page routes:
- Use descriptive, lowercase paths
- Group related pages under common prefixes
- Set appropriate labels for navigation UI
{ path: "/settings/profile", targetType: "page", pageId: "profile_settings_page", label: "Profile Settings", icon: "user",}Default Route
Section titled “Default Route”Always have a default route:
{ path: "/", targetType: "page", pageId: "home_page", isDefault: true, label: "Home", icon: "home",}