FeaturesTemplatesShowcaseTownie
AI
BlogDocsPricing
Log inSign up
lightweight
lightweightglimpse2-runbook-view-glimpse-save-login-react
Remix of lightweight/glimpse2-runbook-view-glimpse-save-login
Public
Like
glimpse2-runbook-view-glimpse-save-login-react
Home
Code
8
_townie
13
backend
7
frontend
5
shared
3
.vtignore
README.md
deno.json
H
main.tsx
Branches
2
Pull requests
Remixes
History
Environment variables
6
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
backend
/
routes
/
README.md
Code
/
backend
/
routes
/
README.md
Search
9/5/2025
Viewing readonly version of main branch: v9
View latest version
README.md

Routes

HTTP route handlers organized by functionality.

Separation of Concerns

Routes are the HTTP transport layer that:

  • Handle HTTP request/response concerns only
  • Extract and validate parameters from HTTP requests
  • Call controllers with clean, typed parameters
  • Transform controller responses into appropriate HTTP responses
  • Handle HTTP status codes, headers, and content types
  • Provide consistent error response formatting

Routes do NOT:

  • Contain business logic (delegate to controllers)
  • Make direct service calls (use controllers as intermediary)
  • Handle environment variables or configuration
  • Perform data transformation beyond HTTP concerns

Architecture Pattern

HTTP Request → Route Handler → Controller → Service → External API
HTTP Response ← Route Handler ← Controller ← Service ← External API

Route Organization

Each route subdirectory should have a _[directory_name].routes.ts file that mounts routes for that section.

Directory Structure

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

Data Flow Patterns

1. API Route Pattern (Recommended)

Characteristics:

  • Extract parameters from URL/body
  • Call controller functions with simple parameters
  • Return JSON responses
  • Handle HTTP status codes based on controller results

Example: Demo API Routes (/api/demo/:id)

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 }

2. Webhook Route Pattern

Characteristics:

  • Parse JSON request bodies
  • Pass Hono Context to controllers (for HTTP-specific needs)
  • Return structured JSON responses
  • Handle webhook-specific error scenarios

Example: URL Update Webhook (POST /tasks/url)

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 }

3. Authentication Route Pattern

Characteristics:

  • Handle authentication middleware context
  • Support both HTML and JSON responses
  • Manage redirects and session state
  • Provide user-friendly error pages

Example: Glimpse Login (GET /glimpse/login)

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:

  • Success: 302 Redirect to user's personalized URL
  • New User: 302 Redirect to /glimpse/thanks
  • Error: 200 HTML error page or 500 JSON error response

4. Health Check Route Pattern

Characteristics:

  • Simple status endpoints
  • Minimal processing
  • Consistent JSON responses

Example: Health Check (GET /api/health)

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 }

Error Handling Patterns

API Routes

// 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); }

Webhook Routes

// 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);

Authentication Routes

  • HTML Error Pages: For user-facing authentication errors
  • JSON Error Responses: For technical/debugging errors
  • Redirects: For successful authentication flows

Route Mounting

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);

Best Practices

Parameter Extraction

  • Use c.req.param() for URL parameters
  • Use await c.req.json() for request bodies
  • Validate required parameters before calling controllers

Response Formatting

  • Return raw data for successful API calls
  • Include error context for debugging
  • Use appropriate HTTP status codes
  • Maintain consistent response structures

Error Responses

  • Provide user-friendly error messages
  • Include technical details for debugging
  • Use appropriate HTTP status codes (400 for client errors, 500 for server errors)
  • Log errors for monitoring and debugging
Go to top
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Product
FeaturesPricing
Developers
DocsStatusAPI ExamplesNPM Package Examples
Explore
ShowcaseTemplatesNewest ValsTrending ValsNewsletter
Company
AboutBlogCareersBrandhi@val.town
Terms of usePrivacy policyAbuse contact
© 2025 Val Town, Inc.