FeaturesTemplatesShowcaseTownie
AI
BlogDocsPricing
Log inSign up
lightweight

lightweight

glimpse2-runbook

Public
Like
glimpse2-runbook
Home
Code
4
_townie
12
.vtignore
deno.json
main.tsx
Branches
2
Pull requests
Remixes
3
History
Environment variables
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
/
_townie
/
04-glimpse.md
Code
/
_townie
/
04-glimpse.md
Search
8/5/2025
Viewing readonly version of main branch: v23
View latest version
04-glimpse.md

Instructions for Adding /views/glimpse/:id Endpoint

Here are the step-by-step instructions that would lead directly to the correct, clean implementation:

1. Analyze the Requirements

  • Endpoint: GET /views/glimpse/:id
  • Authentication: Required (existing Google OAuth)
  • Input: Notion page ID (not database ID)
  • Output: JSON response with full service response (minus UI elements)
  • Data source: Notion page properties

2. Examine Current Architecture

Check existing services to understand data access patterns

cat /backend/services/notion.service.ts

Check existing routes structure

cat /backend/routes/views/\_views.routes.ts

Understand authentication flow

cat /main.tsx # Look for auth middleware setup

3. Identify Missing Service Method

  • Current service has getDatabaseById() for database metadata
  • Need getPageById() for individual page data
  • Service should return full Notion response for flexibility

4. Add Service Method First

// Add to /backend/services/notion.service.ts
export async function getPageById(pageId: string) {
  try {
    const response = await notion.pages.retrieve({
      page_id: pageId,
    });
    return {
      success: true,
      data: response,
      timestamp: new Date().toISOString(),
    };
  } catch (error) {
    return {
      success: false,
      error: error.message,
      timestamp: new Date().toISOString(),
    };
  }
}

5. Create Controller with Minimal Processing

// Create /backend/controllers/glimpse.controller.ts
import { Context } from "npm:hono@3.12.12";
import { getPageById } from "../services/notion.service.ts";

export async function glimpseHandler(c: Context) {
const id = c.req.param("id");

if (!id) {
  return c.json({ error: "Demo ID is required" }, 400);
}

const result = await getPageById(id);

if (!result.success) {
  return c.json({ error: "Failed to fetch demo data", details: result.error }, 500);
}

// Filter out button properties from the response
if (result.data?.properties) {
  const filteredProperties = Object.fromEntries(
  Object.entries(result.data.properties).filter(([key, value]) => value?.type !== "button")
);

    result.data.properties = filteredProperties;

  }

  return c.json(result);
}

6. Add Route

// Update /backend/routes/views/\_views.routes.ts
import { Hono } from "npm:hono@3.12.12";
import { glimpseHandler } from "../../controllers/glimpse.controller.ts";

const app = new Hono();

app.get("/glimpse/:id", glimpseHandler);

export default app;

7. Update Documentation

Add to /backend/routes/views/README.md

GET /views/glimpse/:id

  • Purpose: Returns Notion page data as JSON (filtered for data consumption)
  • Authentication: Required (Google OAuth)
  • Parameters: id - Notion page ID
  • Response: Service response object with Notion page data (button properties removed)
  • Filtering: Removes UI-specific properties (type: "button") for cleaner data consumption

8. Key Design Principles

āœ… Controller Best Practices:

  • Single Responsibility: Controller handles HTTP concerns + minimal data cleanup
  • Thin Layer: Minimal processing, focused on improving data consumption
  • Useful Filtering: Remove UI elements that don't belong in data APIs
  • Consistent Error Handling: Standard error response format

āœ… Service Layer:

  • Data Access: Handle all Notion API interactions
  • Consistent Response Format: Always return {success, data/error, timestamp}
  • Raw Data: Return unfiltered data from external APIs

āœ… Separation of Concerns:

  • Controller: HTTP validation, routing, error responses, basic data cleanup
  • Service: External API calls, data retrieval
  • Client: Complex data processing, extraction, formatting

9. Response Structure

{ "success": true, "data": { "object": "page", "id": "notion-page-id", "properties": { "Name": { "type": "title", "title": [{"plain_text": "Demo Name"}] }, "Status": { "type": "select", "select": {"name": "Active"} } // Button properties filtered out } }, "timestamp": "2025-07-15T17:25:00.000Z" }

10. Key Decision Points

āœ… Correct Approach:

  • Data Source: Use notion.pages.retrieve() for page data
  • Controller Logic: Keep minimal but include useful data cleanup
  • Property Filtering: Remove UI-specific elements (buttons) that don't belong in data APIs
  • Error Handling: Consistent service response pattern

āœ… Appropriate Controller Processing:

  • UI Element Removal: Filter out button properties (not data)
  • Security Cleanup: Remove potentially sensitive UI configurations
  • Performance: Reduce payload size by removing unnecessary properties

āŒ Avoid These Mistakes:

  • Over-processing: Don't extract/transform business data in controller
  • Tight Coupling: Don't assume specific property names or structures
  • Inconsistent Responses: Don't create custom response formats
  • Mixed Responsibilities: Don't mix HTTP handling with complex business logic

11. Testing Strategy

Test authentication (should show login page)

curl /views/glimpse/test-id

Test with valid Notion page ID (after auth)

curl -H "Cookie: auth-cookie" /views/glimpse/actual-notion-page-id

Verify button properties are filtered out

Response should not contain any properties with "type": "button"

12. Benefits of This Approach

  • Clean Data: Removes UI clutter from data API responses
  • Maintainable: Clear separation between layers with focused responsibilities
  • Flexible: Client can still extract any business data from Notion response
  • Consistent: Follows existing service response patterns
  • Secure: Prevents exposure of UI configurations
  • Performance: Smaller payloads without unnecessary UI properties
  • Future-proof: Easy to extend filtering logic for other UI property types

13. When to Add Controller Processing

āœ… Good reasons to process in controller:

  • Remove UI-specific elements (buttons, formulas for display)
  • Filter sensitive configuration data
  • Remove properties that are never useful for data consumption
  • Basic security/privacy filtering

āŒ Avoid processing in controller:

  • Complex business logic transformations
  • Data extraction that depends on specific use cases
  • Heavy computational processing
  • Application-specific data formatting
  • This approach creates a clean, maintainable endpoint that provides useful data filtering while maintaining architectural best practices and keeping the controller focused on its core responsibilities.
FeaturesVersion controlCode intelligenceCLI
Use cases
TeamsAI agentsSlackGTM
ExploreDocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareersBrandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Terms of usePrivacy policyAbuse contact
Ā© 2025 Val Town, Inc.