Skip to main content

Combining Routers

Organize your API by combining multiple routers using the new tRPC-style router() function. Routers can be nested, and paths combine automatically.

Basic Router Combination

import { router, publicProcedure, createServer } from "@alt-stack/server-hono";
import { z } from "zod";

// User routes
const userRouter = router({
"{id}": publicProcedure
.input({
params: z.object({
id: z.string(),
}),
})
.output(
z.object({
id: z.string(),
name: z.string(),
})
)
.get((opts) => {
const { input } = opts;
return { id: input.id, name: "Alice" };
}),

create: publicProcedure
.input({
body: z.object({
name: z.string(),
}),
})
.output(
z.object({
id: z.string(),
})
)
.post((opts) => {
return { id: "1" };
}),
});

// Post routes
const postsRouter = router({
list: publicProcedure
.output(
z.array(
z.object({
id: z.string(),
title: z.string(),
})
)
)
.get(() => {
return [{ id: "1", title: "Hello World" }];
}),
});

// Combine routers - keys become path prefixes
const appRouter = router({
users: userRouter, // Routes prefixed with /users
posts: postsRouter, // Routes prefixed with /posts
});

const app = createServer({
api: appRouter,
});

// Routes available at:
// - GET /api/users/{id}
// - POST /api/users/create
// - GET /api/posts/list

Nested Routers

Routers can be nested within other routers. Paths combine automatically:

import { router, publicProcedure } from "@alt-stack/server-hono";

const productRouter = router({
"favorites/me": publicProcedure.get(() => {
return [];
}),
});

const userRouter = router({
profile: publicProcedure.get(() => {
return { id: "1" };
}),
});

// Nested routers
const appRouter = router({
products: productRouter, // /products/favorites/me
users: userRouter, // /users/profile
});

// Final paths:
// - GET /products/favorites/me
// - GET /users/profile

Multiple Routers with Same Prefix

You can pass arrays of routers for the same prefix in createServer:

import { router, publicProcedure, createServer } from "@alt-stack/server-hono";

const v1Router = router({
users: publicProcedure.get(() => []),
});

const v2Router = router({
users: publicProcedure.get(() => []),
});

const app = createServer({
api: [v1Router, v2Router], // Both routers prefixed with /api
});

This is useful for versioning APIs or organizing routes by feature.

Nested Routes with Compound Paths

To achieve nested routes like /api/v1/* and /api/v2/*, use compound prefixes in createServer:

import { router, publicProcedure, createServer } from "@alt-stack/server-hono";

const v1Router = router({
users: publicProcedure.get(() => []),
});

const v2Router = router({
users: publicProcedure.get(() => []),
});

const adminRouter = router({
settings: publicProcedure.get(() => []),
});

const app = createServer({
"api/v1": v1Router,
"api/v2": v2Router,
admin: adminRouter,
});

Results in routes like:

  • /api/v1/users - All v1Router routes
  • /api/v2/users - All v2Router routes
  • /admin/settings - All adminRouter routes