WIP! A BB-style forum, on the ATmosphere! We're still working... we'll be back soon when we have something to show off!
node typescript hono htmx atproto
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs: add error handling standards to CLAUDE.md

Add comprehensive error handling patterns based on PR #13 review learnings:
- API route handler requirements (validation, try-catch, HTTP status codes)
- Catch block guidelines (specific types, re-throw unexpected errors)
- Helper function conventions (null returns, error re-throwing)
- Defensive programming checklist (limits, deleted filtering, ordering)
- Global error handler pattern

These standards codify patterns that emerged from multi-round PR reviews,
helping future PRs get error handling right on the first iteration.

Malpercio 8c244567 9a6b684e

+127
+127
CLAUDE.md
··· 84 84 - **Glob expansion in npm scripts:** `@atproto/lex-cli` needs file paths, not globs. Use `bash -c 'shopt -s globstar && ...'` to expand `**/*.json` in npm scripts. 85 85 - **`.env` loading:** Dev and spike scripts use Node's `--env-file=../../.env` flag to load the root `.env` file. No `dotenv` dependency needed. 86 86 87 + ## Error Handling Standards 88 + 89 + Follow these patterns for robust, debuggable production code: 90 + 91 + ### API Route Handlers 92 + 93 + **Required for all database-backed endpoints:** 94 + 1. Validate input parameters before database queries (return 400 for invalid input) 95 + 2. Wrap database queries in try-catch with structured logging 96 + 3. Check resource existence explicitly (return 404 for missing resources) 97 + 4. Return proper HTTP status codes (400/404/500, not always 500) 98 + 99 + **Example pattern:** 100 + ```typescript 101 + export function createForumRoutes(ctx: AppContext) { 102 + return new Hono().get("/", async (c) => { 103 + try { 104 + const [forum] = await ctx.db 105 + .select() 106 + .from(forums) 107 + .where(eq(forums.rkey, "self")) 108 + .limit(1); 109 + 110 + if (!forum) { 111 + return c.json({ error: "Forum not found" }, 404); 112 + } 113 + 114 + return c.json({ /* success response */ }); 115 + } catch (error) { 116 + console.error("Failed to query forum metadata", { 117 + operation: "GET /api/forum", 118 + error: error instanceof Error ? error.message : String(error), 119 + }); 120 + return c.json( 121 + { error: "Failed to retrieve forum metadata. Please try again later." }, 122 + 500 123 + ); 124 + } 125 + }); 126 + } 127 + ``` 128 + 129 + ### Catch Block Guidelines 130 + 131 + **DO:** 132 + - Catch specific error types when possible (`instanceof RangeError`, `instanceof SyntaxError`) 133 + - Re-throw unexpected errors (don't swallow programming bugs like `TypeError`) 134 + - Log with structured context: operation name, relevant IDs, error message 135 + - Return user-friendly messages (no stack traces in production) 136 + 137 + **DON'T:** 138 + - Use bare `catch` blocks that hide all error types 139 + - Return generic "try again later" for client errors (400) vs server errors (500) 140 + - Fabricate data in catch blocks (return null or fail explicitly) 141 + - Use empty catch blocks or catch without logging 142 + 143 + ### Helper Functions 144 + 145 + **Validation helpers should:** 146 + - Return `null` for invalid input (not throw) 147 + - Re-throw unexpected errors 148 + - Use specific error type checking 149 + 150 + **Example:** 151 + ```typescript 152 + export function parseBigIntParam(value: string): bigint | null { 153 + try { 154 + return BigInt(value); 155 + } catch (error) { 156 + if (error instanceof RangeError || error instanceof SyntaxError) { 157 + return null; // Expected error for invalid input 158 + } 159 + throw error; // Unexpected error - let it bubble up 160 + } 161 + } 162 + ``` 163 + 164 + **Serialization helpers should:** 165 + - Avoid silent fallbacks (log warnings if fabricating data) 166 + - Prefer returning `null` over fake values (`"0"`, `new Date()`) 167 + - Document fallback behavior in JSDoc if unavoidable 168 + 169 + ### Defensive Programming 170 + 171 + **All list queries must have defensive limits:** 172 + ```typescript 173 + .from(categories) 174 + .orderBy(categories.sortOrder) 175 + .limit(1000); // Prevent memory exhaustion on unbounded queries 176 + ``` 177 + 178 + **Filter deleted/soft-deleted records:** 179 + ```typescript 180 + .where(and( 181 + eq(posts.rootPostId, topicId), 182 + eq(posts.deleted, false) // Never show deleted content to users 183 + )) 184 + ``` 185 + 186 + **Use ordering for consistent results:** 187 + ```typescript 188 + .orderBy(asc(posts.createdAt)) // Chronological order for replies 189 + ``` 190 + 191 + ### Global Error Handler 192 + 193 + The Hono app must have a global error handler as a safety net: 194 + ```typescript 195 + app.onError((err, c) => { 196 + console.error("Unhandled error in route handler", { 197 + path: c.req.path, 198 + method: c.req.method, 199 + error: err.message, 200 + stack: err.stack, 201 + }); 202 + return c.json( 203 + { 204 + error: "An internal error occurred. Please try again later.", 205 + ...(process.env.NODE_ENV !== "production" && { 206 + details: err.message, 207 + }), 208 + }, 209 + 500 210 + ); 211 + }); 212 + ``` 213 + 87 214 ## Documentation & Project Tracking 88 215 89 216 **Keep these synchronized when completing work:**