Core Concepts: Routing

Routing in Jetpath is designed to be intuitive and fast, primarily relying on convention over configuration through a file-based system. This means your project’s file structure and how you name your exported functions directly determine your API endpoints.


Key Concepts

1. Source Directory

When you initialize Jetpath, you specify a source directory. Jetpath watches this directory for .jet.ts files containing your route handlers.

// server.ts
import { Jetpath } from "jetpath";

const app = new Jetpath({ source: "./src", // Jetpath looks for routes inside the 'src' folder // … other options });

app.listen();

2. File and Folder Mapping

The path to a .jet.ts file within the source directory directly maps to the URL path segments.

3. Handler Files (.jet.ts)

Files ending with .jet.ts are scanned by Jetpath for exported functions that define route handlers. Other .ts or .js files in the source directory are ignored for routing purposes (but can still be imported by your handlers).

4. Export Naming Convention

The core convention lies in the names of the exported functions within your .jet.ts files.

Examples from tests/app.jet.ts:

5. Index Routes

Files named index.jet.ts represent the root path segment for their directory.

6. Path Parameters ($paramName)

To capture dynamic segments in the URL, use a $ prefix followed by the parameter name within a filename segment or an exported function name segment.

7. Catch-all / Greedy Routes ($)

To match multiple path segments at the end of a route, use $ at the end of a filename segment or export name segment.

8. WebSocket Routes (WS_)

Define WebSocket handlers using the WS_ prefix in the export name.

// Inside src/live.jet.ts (or similar)
export const WS_live: JetFunc = (ctx) => {
    const conn = ctx.connection!; // Access WebSocket connection
    conn.addEventListener("open", (socket) => { /* ... */ });
    conn.addEventListener("message", (socket, event) => { /* ... */ });
    // ...
}; // Maps WebSocket connections to ws://your-host/live [cite: tests/app.jet.ts]

Route Precedence

Jetpath follows standard routing precedence rules:

  1. Static routes (e.g., /pets/search) are matched before dynamic routes (/pets/:id).
  2. More specific dynamic routes (e.g., /pets/by/:id) are matched before catch-all routes (/pets/search/$).
  3. (Need to confirm) If multiple exports in the same file could match the same METHOD + Path, the behavior might be unpredictable or follow source code order. It’s best practice to ensure unique METHOD + Path combinations.

Advanced Routing

Explicit Overrides (Recommended Practice)

While conventions are powerful, complex scenarios might benefit from explicit definitions. Using a defineHandler helper (if implemented based on recommendations) allows overriding inferred paths or methods:

// Recommended pattern for complex cases
import { defineHandler } from "jetpath";
import { PetSchema } from "./schemas"; // Assuming Zod/TypeBox schema

export const updatePetStatus = defineHandler({ // Explicitly define the route if convention doesn't fit well route: { method: 'PATCH', path: '/pets/:id/status' }, schema: { params: t.object({ id: t.string() }), body: t.object({ available: t.boolean() }) }, handler: async (ctx) => { const { id } = ctx.params; // Typed based on schema const { available } = ctx.body; // Typed and potentially pre-validated // … logic … } });

Programmatic Routing

(This section would detail any API provided by Jetpath for adding routes programmatically via app.addRoute(...) or similar, if available. This is useful for dynamic route generation or plugin integrations.)


Next Steps