Skip to Content
GuidesBuilding API Routes

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:

  1. Static assets (/assets/*) — Served directly from Cloudflare’s CDN
  2. API routes (/api/*) — Handled by the Hono app in the Worker
  3. Everything else (GET) — Returns index.html for SPA client-side routing
  4. 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 }); });