Patterns and Anti-Patterns
Prerequisites: Familiarity with Jaypie basics
Overview
Section titled “Overview”This page documents Jaypie coding patterns to follow and anti-patterns to avoid.
Error Handling
Section titled “Error Handling”Do: Use Jaypie Errors
Section titled “Do: Use Jaypie Errors”import { NotFoundError, BadRequestError } from "jaypie";
if (!user) throw NotFoundError("User not found");if (!email) throw BadRequestError("Email required");Don’t: Vanilla Errors
Section titled “Don’t: Vanilla Errors”// Badthrow new Error("User not found");throw new Error("Email required");Do: Log Then Throw
Section titled “Do: Log Then Throw”import { BadGatewayError, log } from "jaypie";
try { await externalApi.call();} catch (error) { log.error("External API failed"); log.var({ error: error.message }); throw BadGatewayError();}Don’t: Expose Internal Details
Section titled “Don’t: Expose Internal Details”// Bad - exposes stack tracethrow InternalError(error.message);throw InternalError(`DB error: ${dbError.stack}`);Logging
Section titled “Logging”Do: Use Log Levels Correctly
Section titled “Do: Use Log Levels Correctly”// Happy path = trace onlylog.trace("[getUser] fetching");const user = await db.findById(id);log.trace("[getUser] found");
// Unexpected but handled = debugif (!cached) { log.debug("[getUser] cache miss");}
// Problems = warn/errorlog.error("Payment service down");Don’t: Log Everything as Info
Section titled “Don’t: Log Everything as Info”// Badlog.info("Starting function");log.info("Got user");log.info("Returning result");Do: Single Key Per var()
Section titled “Do: Single Key Per var()”log.var({ userId: "123" });log.var({ orderId: "456" });Don’t: Multiple Keys
Section titled “Don’t: Multiple Keys”// Badlog.var({ userId: "123", orderId: "456", status: "active" });Do: Function Prefix
Section titled “Do: Function Prefix”log.trace("[processOrder] starting");log.trace("[processOrder] validated");log.trace("[processOrder] complete");Function Parameters
Section titled “Function Parameters”Do: Object Parameters
Section titled “Do: Object Parameters”function createUser({ name, email, role }) { // ...}
function fetchUser(userId, { includeProfile } = {}) { // Single required + options object OK}Don’t: Ordered Parameters
Section titled “Don’t: Ordered Parameters”// Badfunction createUser(name, email, role, active, createdBy) { // ...}Imports and Organization
Section titled “Imports and Organization”Do: Alphabetize
Section titled “Do: Alphabetize”import { BadRequestError, log, NotFoundError, uuid } from "jaypie";
const config = { apiKey: process.env.API_KEY, database: process.env.DATABASE, timeout: 5000,};Don’t: Random Order
Section titled “Don’t: Random Order”// Badimport { log, uuid, BadRequestError, NotFoundError } from "jaypie";Constants
Section titled “Constants”Do: Named Constants
Section titled “Do: Named Constants”const DEFAULT_TIMEOUT = 5000;const MAX_RETRIES = 3;const API_VERSION = "v1";
function fetchData() { return fetch(url, { timeout: DEFAULT_TIMEOUT });}Don’t: Magic Numbers
Section titled “Don’t: Magic Numbers”// Badfunction fetchData() { return fetch(url, { timeout: 5000 });}Testing
Section titled “Testing”Do: Seven Sections
Section titled “Do: Seven Sections”describe("Function", () => { describe("Base Cases", () => { /* ... */ }); describe("Error Conditions", () => { /* ... */ }); describe("Security", () => { /* ... */ }); describe("Observability", () => { /* ... */ }); describe("Happy Paths", () => { /* ... */ }); describe("Features", () => { /* ... */ }); describe("Specific Scenarios", () => { /* ... */ });});Do: Test Observability
Section titled “Do: Test Observability”describe("Observability", () => { it("does not log above trace on success", async () => { await handler(); expect(log.debug).not.toHaveBeenCalled(); expect(log.warn).not.toHaveBeenCalled(); expect(log.error).not.toHaveBeenCalled(); });});Do: Sibling Test Files
Section titled “Do: Sibling Test Files”src/├── utils/│ ├── helper.ts│ └── helper.spec.ts # Sibling, not in __tests__Don’t: Separate Test Directory
Section titled “Don’t: Separate Test Directory”// Badsrc/├── utils/│ └── helper.ts__tests__/└── utils/ └── helper.spec.tsHandler Patterns
Section titled “Handler Patterns”Do: Use req.locals
Section titled “Do: Use req.locals”expressHandler( async (req) => { return { user: req.locals.user }; }, { setup: [ async (req) => { req.locals.user = await loadUser(req); }, ], });Do: Return Values (Not res.json)
Section titled “Do: Return Values (Not res.json)”// GoodexpressHandler(async (req) => { return { data: result };});
// BadexpressHandler(async (req, res) => { res.json({ data: result });});Type Safety
Section titled “Type Safety”Do: Handle Optional Parameters
Section titled “Do: Handle Optional Parameters”function process(value?: string) { if (!value) { throw BadRequestError("Value required"); } // Now value is string, not string | undefined return value.toUpperCase();}Do: Use Type Guards
Section titled “Do: Use Type Guards”if (isJaypieError(error)) { return res.status(error.status).json(error.body());}Avoid Over-Engineering
Section titled “Avoid Over-Engineering”Do: Minimal Changes
Section titled “Do: Minimal Changes”// User asked to add validationfunction createUser({ email }) { if (!email.includes("@")) { throw BadRequestError("Invalid email"); } // Just add validation, don't refactor everything}Don’t: Add Unnecessary Abstractions
Section titled “Don’t: Add Unnecessary Abstractions”// Bad - user just asked to add validation// Don't create EmailValidator class// Don't add validation framework// Don't refactor surrounding codeDo: Delete Unused Code
Section titled “Do: Delete Unused Code”// If removing a feature, delete it completely// Don't leave commented code// Don't add backwards-compat shimsEnvironment
Section titled “Environment”Do: Use Jaypie Environment Checks
Section titled “Do: Use Jaypie Environment Checks”import { isProductionEnv, isLocalEnv } from "jaypie";
if (isProductionEnv()) { // Production behavior}Don’t: Direct NODE_ENV Checks
Section titled “Don’t: Direct NODE_ENV Checks”// Badif (process.env.NODE_ENV === "production") { // ...}Related
Section titled “Related”- Error Handling - Error patterns
- Logging - Logging patterns
- Testing - Testing patterns
- Handler Lifecycle - Handler patterns