Skip to content
On this page

Routing API

Complete API reference for Verb's routing system including HTTP methods, route parameters, and middleware.

Core Routing Methods

app.get(path, ...handlers)

Register a GET route handler.

typescript
app.get(path: string, ...handlers: RouteHandler[]): VerbApplication

Parameters:

  • path - Route path with optional parameters (e.g., /users/:id)
  • handlers - One or more route handler functions

Example:

typescript
app.get("/users", (req, res) => {
  res.json({ users: [] });
});

app.get("/users/:id", (req, res) => {
  const { id } = req.params;
  res.json({ userId: id });
});

app.post(path, ...handlers)

Register a POST route handler.

typescript
app.post(path: string, ...handlers: RouteHandler[]): VerbApplication

Example:

typescript
app.post("/users", (req, res) => {
  const user = createUser(req.body);
  res.status(201).json(user);
});

app.put(path, ...handlers)

Register a PUT route handler.

typescript
app.put(path: string, ...handlers: RouteHandler[]): VerbApplication

app.patch(path, ...handlers)

Register a PATCH route handler.

typescript
app.patch(path: string, ...handlers: RouteHandler[]): VerbApplication

app.delete(path, ...handlers)

Register a DELETE route handler.

typescript
app.delete(path: string, ...handlers: RouteHandler[]): VerbApplication

app.head(path, ...handlers)

Register a HEAD route handler.

typescript
app.head(path: string, ...handlers: RouteHandler[]): VerbApplication

app.options(path, ...handlers)

Register an OPTIONS route handler.

typescript
app.options(path: string, ...handlers: RouteHandler[]): VerbApplication

app.all(path, ...handlers)

Register a handler for all HTTP methods.

typescript
app.all(path: string, ...handlers: RouteHandler[]): VerbApplication

Example:

typescript
app.all("/api/*", authenticate); // Apply to all methods

Route Patterns

Static Routes

typescript
app.get("/about", handler);
app.get("/api/users", handler);

Route Parameters

typescript
// Single parameter
app.get("/users/:id", (req, res) => {
  const { id } = req.params;
});

// Multiple parameters
app.get("/users/:userId/posts/:postId", (req, res) => {
  const { userId, postId } = req.params;
});

// Optional parameters
app.get("/posts/:id?", (req, res) => {
  const { id } = req.params; // undefined if not provided
});

Wildcard Routes

typescript
// Catch-all
app.get("/files/*", (req, res) => {
  const path = req.params["*"]; // Everything after /files/
});

// Named wildcards
app.get("/api/*/users", (req, res) => {
  const version = req.params["*"];
});

Regular Expression Routes

typescript
// Custom pattern
app.get(/.*fly$/, (req, res) => {
  // Matches any path ending with "fly"
});

// With capture groups
app.get(/^\/users\/(\d+)$/, (req, res) => {
  const id = req.params[0]; // First capture group
});

Route Handler Types

Basic Handler

typescript
type RouteHandler = (
  req: VerbRequest,
  res: VerbResponse,
  next?: NextFunction
) => void | Promise<void>;

Middleware Handler

typescript
type MiddlewareHandler = (
  req: VerbRequest,
  res: VerbResponse,
  next: NextFunction
) => void | Promise<void>;

Error Handler

typescript
type ErrorHandler = (
  error: Error,
  req: VerbRequest,
  res: VerbResponse,
  next: NextFunction
) => void | Promise<void>;

Middleware

app.use(middleware)

Register global middleware.

typescript
app.use(middleware: MiddlewareHandler): VerbApplication

Example:

typescript
app.use((req, res, next) => {
  console.log(`${req.method} ${req.path}`);
  next();
});

app.use(path, middleware)

Register middleware for specific paths.

typescript
app.use(path: string, middleware: MiddlewareHandler): VerbApplication

Example:

typescript
app.use("/api", authenticate);
app.use("/admin", authorize("admin"));

Router Class

Creating Routers

typescript
import { Router } from "verb";

const router = new Router();

router.get("/users", getUsersHandler);
router.post("/users", createUserHandler);

app.use("/api", router);

Router Methods

All the same methods as the main app:

typescript
router.get(path, ...handlers)
router.post(path, ...handlers)
router.put(path, ...handlers)
router.patch(path, ...handlers)
router.delete(path, ...handlers)
router.head(path, ...handlers)
router.options(path, ...handlers)
router.all(path, ...handlers)
router.use(middleware)
router.use(path, middleware)

Router Options

typescript
const router = new Router({
  caseSensitive: false,    // Case-sensitive routing
  mergeParams: false,      // Merge parent params
  strict: false            // Strict routing
});

Route Matching

Match Priority

Routes are matched in the order they are defined:

typescript
app.get("/users/new", handler1);     // Higher priority
app.get("/users/:id", handler2);     // Lower priority

Path Normalization

Paths are normalized automatically:

typescript
app.get("/users/", handler);    // Same as "/users"
app.get("/users", handler);     // Same as "/users/"

Advanced Routing

Conditional Routing

typescript
app.get("/users/:id", 
  (req, res, next) => {
    if (!isValidId(req.params.id)) {
      return res.status(400).json({ error: "Invalid ID" });
    }
    next();
  },
  getUserHandler
);

Route-specific Middleware

typescript
app.get("/protected", 
  authenticate,
  authorize("admin"),
  protectedHandler
);

Error Handling

typescript
app.get("/users/:id", async (req, res, next) => {
  try {
    const user = await getUser(req.params.id);
    res.json(user);
  } catch (error) {
    next(error); // Pass to error handler
  }
});

// Error handler
app.use((error, req, res, next) => {
  res.status(500).json({ error: error.message });
});

Bun Native Routes

withRoutes(routes)

Configure Bun-style routes.

typescript
app.withRoutes(routes: BunRoutes): VerbApplication

Example:

typescript
import homepage from "./index.html";

app.withRoutes({
  "/": homepage,
  "/api/users": {
    GET: async () => Response.json(await getUsers()),
    POST: async (req) => {
      const user = await createUser(await req.json());
      return Response.json(user, { status: 201 });
    }
  },
  "/api/users/:id": {
    GET: async (req) => {
      const user = await getUser(req.params.id);
      return Response.json(user);
    }
  }
});

BunRoutes Type

typescript
type BunRouteHandler = (req: Request) => Response | Promise<Response>;

type BunRoutes = {
  [path: string]: 
    | BunRouteHandler
    | { [method: string]: BunRouteHandler }
    | any; // For HTML imports
};

Route Information

Getting Route Info

typescript
// Get all registered routes
const routes = app.getRoutes();

// Get routes for specific method
const getRoutes = app.getRoutes("GET");

// Check if route exists
const exists = app.hasRoute("GET", "/users");

Route Metadata

typescript
interface RouteInfo {
  method: string;
  path: string;
  handler: RouteHandler;
  middleware: MiddlewareHandler[];
  params: string[];
  regexp: RegExp;
}

Performance Considerations

Route Optimization

typescript
// Prefer specific routes first
app.get("/users/active", getActiveUsers);  // Specific
app.get("/users/:id", getUser);            // Parameter

// Use router for grouped routes
const apiRouter = new Router();
apiRouter.get("/users", getUsers);
apiRouter.post("/users", createUser);
app.use("/api", apiRouter);

Caching Routes

typescript
// Routes are compiled and cached automatically
// No manual optimization needed

Testing Routes

typescript
import { test, expect } from "bun:test";

test("route handling", async () => {
  const app = createServer();
  
  app.get("/test", (req, res) => {
    res.json({ success: true });
  });
  
  const handler = app.createFetchHandler();
  const response = await handler(new Request("http://localhost/test"));
  
  expect(response.status).toBe(200);
  const data = await response.json();
  expect(data.success).toBe(true);
});

Common Patterns

RESTful Routes

typescript
const router = new Router();

router.get("/users", getUsers);           // GET /users
router.get("/users/:id", getUser);        // GET /users/:id
router.post("/users", createUser);        // POST /users
router.put("/users/:id", updateUser);     // PUT /users/:id
router.delete("/users/:id", deleteUser);  // DELETE /users/:id

app.use("/api", router);

Nested Resources

typescript
router.get("/users/:userId/posts", getUserPosts);
router.get("/users/:userId/posts/:id", getUserPost);
router.post("/users/:userId/posts", createUserPost);

API Versioning

typescript
const v1Router = new Router();
const v2Router = new Router();

v1Router.get("/users", getUsersV1);
v2Router.get("/users", getUsersV2);

app.use("/api/v1", v1Router);
app.use("/api/v2", v2Router);

Error Handling

Route Not Found

typescript
// 404 handler (must be last)
app.use((req, res) => {
  res.status(404).json({
    error: "Not Found",
    path: req.path,
    method: req.method
  });
});

Method Not Allowed

typescript
app.use((req, res, next) => {
  const allowedMethods = app.getAllowedMethods(req.path);
  
  if (allowedMethods.length > 0 && !allowedMethods.includes(req.method)) {
    res.header("Allow", allowedMethods.join(", "));
    return res.status(405).json({ error: "Method Not Allowed" });
  }
  
  next();
});

Migration Guide

From Express

typescript
// Express
app.get("/users/:id", (req, res) => {
  res.json({ id: req.params.id });
});

// Verb (same syntax)
app.get("/users/:id", (req, res) => {
  res.json({ id: req.params.id });
});

From Fastify

typescript
// Fastify
fastify.get("/users/:id", async (request, reply) => {
  return { id: request.params.id };
});

// Verb
app.get("/users/:id", (req, res) => {
  res.json({ id: req.params.id });
});

Type Definitions

typescript
interface VerbApplication {
  get(path: string, ...handlers: RouteHandler[]): VerbApplication;
  post(path: string, ...handlers: RouteHandler[]): VerbApplication;
  put(path: string, ...handlers: RouteHandler[]): VerbApplication;
  patch(path: string, ...handlers: RouteHandler[]): VerbApplication;
  delete(path: string, ...handlers: RouteHandler[]): VerbApplication;
  head(path: string, ...handlers: RouteHandler[]): VerbApplication;
  options(path: string, ...handlers: RouteHandler[]): VerbApplication;
  all(path: string, ...handlers: RouteHandler[]): VerbApplication;
  use(middleware: MiddlewareHandler): VerbApplication;
  use(path: string, middleware: MiddlewareHandler): VerbApplication;
  withRoutes(routes: BunRoutes): VerbApplication;
}

interface Router {
  get(path: string, ...handlers: RouteHandler[]): Router;
  post(path: string, ...handlers: RouteHandler[]): Router;
  put(path: string, ...handlers: RouteHandler[]): Router;
  patch(path: string, ...handlers: RouteHandler[]): Router;
  delete(path: string, ...handlers: RouteHandler[]): Router;
  head(path: string, ...handlers: RouteHandler[]): Router;
  options(path: string, ...handlers: RouteHandler[]): Router;
  all(path: string, ...handlers: RouteHandler[]): Router;
  use(middleware: MiddlewareHandler): Router;
  use(path: string, middleware: MiddlewareHandler): Router;
}

Released under the MIT License.