Building API Routes
Add custom API endpoints to your Cloudflare Worker.
Overview
Your Vibekit app includes a Cloudflare Worker powered by Hono . API routes live in worker/index.ts and handle requests at /api/*.
Adding a route
Open worker/index.ts and add routes to the Hono app:
// Public route
app.get("/api/health", (c) => {
return c.json({ status: "ok" });
});
// Protected route (user set by auth middleware)
app.get("/api/me", (c) => {
const user = c.get("user");
if (!user) return c.json({ error: "Unauthorized" }, 401);
return c.json({ user });
});Common patterns
POST with JSON body
app.post("/api/items", async (c) => {
const user = c.get("user");
if (!user) return c.json({ error: "Unauthorized" }, 401);
const body = await c.req.json();
// Process body...
return c.json({ success: true });
});Route parameters
app.get("/api/items/:id", (c) => {
const id = c.req.param("id");
// Fetch item by id...
return c.json({ id });
});Query parameters
app.get("/api/search", (c) => {
const query = c.req.query("q");
const page = parseInt(c.req.query("page") || "1");
// Search...
return c.json({ results: [] });
});Using the Server SDK in routes
import { createServerSDK } from "@myco-dev/sdk/server";
app.get("/api/contacts", async (c) => {
const user = c.get("user");
if (!user) return c.json({ error: "Unauthorized" }, 401);
const sdk = createServerSDK({ MYCO_APP_KEY: c.env.MYCO_APP_KEY }, c.req.raw);
const { records } = await sdk.data.getRecords("contact", { pageSize: 100 });
return c.json({ contacts: records });
});Error handling
app.post("/api/items", async (c) => {
try {
const body = await c.req.json();
if (!body.title) {
return c.json({ error: "Title is required" }, 400);
}
// Create item...
return c.json({ success: true }, 201);
} catch (err) {
return c.json({ error: "Internal server error" }, 500);
}
});Request flow
Understanding how requests are routed:
- Static assets (
/assets/*) — Served directly from Cloudflare’s CDN - API routes (
/api/*) — Handled by the Hono app in the Worker - Everything else (GET) — Returns
index.htmlfor SPA client-side routing - Non-GET unmatched routes — Returns 404
This is configured in the Worker’s fetch handler at the bottom of worker/index.ts.
CORS
The Vibekit template includes CORS middleware for /api/* routes:
app.use("/api/*", cors({
origin: (origin) => origin || "*",
allowHeaders: ["Content-Type", "Authorization"],
allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
credentials: true,
}));Environment bindings
Access Cloudflare bindings through c.env:
app.get("/api/example", (c) => {
const appKey = c.env.MYCO_APP_KEY;
// c.env also gives access to KV, R2, D1, etc. if configured
return c.json({ ok: true });
});