HTTP route handlers organized by functionality.
Routes are the HTTP transport layer that:
Routes do NOT:
HTTP Request → Route Handler → Controller → Service → External API
HTTP Response ← Route Handler ← Controller ← Service ← External API
Each route subdirectory should have a _[directory_name].routes.ts
file that mounts routes for that section.
routes/
├── api/
│ ├── _api.routes.ts # Mounts all API routes
│ └── README.md
├── tasks/
│ ├── _tasks.routes.ts # Mounts webhook routes
│ └── README.md
├── views/
│ ├── _views.routes.ts # Mounts HTML view routes
│ └── README.md
└── glimpse/
├── _glimpse.routes.ts # Mounts authentication routes
└── README.md
Characteristics:
HTTP Request Data:
// URL Parameters
params: { id: string }
// Example: GET /api/demo/abc123/properties
Route Processing:
app.get("/demo/:id/properties", async (c) => {
// 1. Extract parameters from HTTP request
const id = c.req.param("id");
// 2. Call controller with clean parameters
const result = await getDemoProperties(id);
// 3. Transform controller response to HTTP response
if (!result.success) {
return c.json({
error: result.error,
details: result.details
}, result.error === "Page ID is required" ? 400 : 500);
}
// 4. Return successful data
return c.json(result.data);
});
HTTP Response Data:
// Success Response (200)
{
id: string,
properties: { [key: string]: NotionPropertyValue },
// ... filtered page data
}
// Error Response (400/500)
{
error: string,
details?: string
}
Characteristics:
HTTP Request Data:
// Request Body (JSON)
{
data?: { id: string },
id?: string,
page_id?: string
}
// Request Headers
{
host: string,
"content-type": "application/json"
}
Route Processing:
app.post("/url", handleUrlWebhook);
// Controller handles full HTTP context due to webhook complexity
HTTP Response Data:
// Success Response (200)
{
success: true,
message: "Page URL updated successfully",
pageId: string,
url: string,
timestamp: string
}
// Error Response (400/500)
{
success: false,
error: string,
details?: string
}
Characteristics:
HTTP Request Data:
// From Authentication Middleware
context: {
userEmail: string
}
// Environment Configuration
{
GLANCE_DEMOS_DB_ID: string
}
Route Processing:
app.get("/login", glimpseLoginHandler);
// Controller handles full HTTP context for redirects and HTML responses
HTTP Response Data:
302 Redirect
to user's personalized URL302 Redirect
to /glimpse/thanks
200 HTML
error page or 500 JSON
error responseCharacteristics:
HTTP Request Data: None
Route Processing:
app.get("/health", async (c) => {
const healthStatus = await getHealthStatus();
return c.json(healthStatus);
});
HTTP Response Data:
{
status: "healthy" | "unhealthy",
timestamp: string,
// ... additional health metrics
}
// Validation Errors (400)
if (!result.success && result.error === "Page ID is required") {
return c.json({ error: result.error }, 400);
}
// Server Errors (500)
if (!result.success) {
return c.json({
error: result.error,
details: result.details
}, 500);
}
// Bad Request (400)
return c.json({
success: false,
error: "Page ID is required in webhook payload"
}, 400);
// Server Error (500)
return c.json({
success: false,
error: "Internal server error processing webhook",
details: error.message
}, 500);
Each route module exports a Hono app that gets mounted in the main application:
// _api.routes.ts
import { Hono } from "npm:hono@3.12.12";
import { getDemoProperties, getDemoFull } from "../../controllers/demo.controller.ts";
const app = new Hono();
app.get("/demo/:id/properties", async (c) => {
// Route implementation
});
export default app;
// main.tsx
import apiRoutes from "./backend/routes/api/_api.routes.ts";
import taskRoutes from "./backend/routes/tasks/_tasks.routes.ts";
app.route("/api", apiRoutes);
app.route("/tasks", taskRoutes);
c.req.param()
for URL parametersawait c.req.json()
for request bodies