{
  "schemaVersion": "1.0",
  "item": {
    "slug": "nodejs-patterns",
    "name": "Nodejs Patterns",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/wpank/nodejs-patterns",
    "canonicalUrl": "https://clawhub.ai/wpank/nodejs-patterns",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/nodejs-patterns",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=nodejs-patterns",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "README.md",
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "slug": "nodejs-patterns",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-05-06T04:22:30.246Z",
      "expiresAt": "2026-05-13T04:22:30.246Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=nodejs-patterns",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=nodejs-patterns",
        "contentDisposition": "attachment; filename=\"nodejs-patterns-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null,
        "slug": "nodejs-patterns"
      },
      "scope": "item",
      "summary": "Item download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this item.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/nodejs-patterns"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/nodejs-patterns",
    "agentPageUrl": "https://openagent3.xyz/skills/nodejs-patterns/agent",
    "manifestUrl": "https://openagent3.xyz/skills/nodejs-patterns/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/nodejs-patterns/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Node.js Backend Patterns",
        "body": "Patterns for building scalable, maintainable Node.js backend applications with TypeScript."
      },
      {
        "title": "NEVER",
        "body": "NEVER store secrets in code - Use environment variables, never hardcode credentials\nNEVER skip input validation - Validate all input at the middleware layer with Zod/Joi\nNEVER expose error details in production - Return generic messages, log details server-side\nNEVER use any type - TypeScript types prevent runtime errors\nNEVER skip error handling - Always wrap async handlers, use global error middleware\nNEVER use sync operations - Use async/await for I/O, never fs.readFileSync in handlers\nNEVER trust client input - Sanitize, validate, and parameterize all queries"
      },
      {
        "title": "When to Use",
        "body": "Building REST APIs with Express or Fastify\nSetting up middleware pipelines and error handling\nImplementing authentication and authorization\nIntegrating databases with connection pooling and transactions\nAdding validation, caching, and rate limiting"
      },
      {
        "title": "Project Structure — Layered Architecture",
        "body": "src/\n├── controllers/     # Handle HTTP requests/responses\n├── services/        # Business logic\n├── repositories/    # Data access layer\n├── models/          # Data models and types\n├── middleware/      # Auth, validation, logging, errors\n├── routes/          # Route definitions\n├── config/          # Database, cache, env configuration\n└── utils/           # Helpers, custom errors, response formatting\n\nControllers handle HTTP concerns, services contain business logic, repositories abstract data access. Each layer only calls the layer below it."
      },
      {
        "title": "Express Setup",
        "body": "import express from \"express\";\nimport helmet from \"helmet\";\nimport cors from \"cors\";\nimport compression from \"compression\";\n\nconst app = express();\n\napp.use(helmet());\napp.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(\",\") }));\napp.use(compression());\napp.use(express.json({ limit: \"10mb\" }));\napp.use(express.urlencoded({ extended: true, limit: \"10mb\" }));"
      },
      {
        "title": "Fastify Setup",
        "body": "import Fastify from \"fastify\";\nimport helmet from \"@fastify/helmet\";\nimport cors from \"@fastify/cors\";\n\nconst fastify = Fastify({\n  logger: { level: process.env.LOG_LEVEL || \"info\" },\n});\n\nawait fastify.register(helmet);\nawait fastify.register(cors, { origin: true });\n\n// Type-safe routes with built-in schema validation\nfastify.post<{ Body: { name: string; email: string } }>(\n  \"/users\",\n  {\n    schema: {\n      body: {\n        type: \"object\",\n        required: [\"name\", \"email\"],\n        properties: {\n          name: { type: \"string\", minLength: 1 },\n          email: { type: \"string\", format: \"email\" },\n        },\n      },\n    },\n  },\n  async (request) => {\n    const { name, email } = request.body;\n    return { id: \"123\", name };\n  },\n);"
      },
      {
        "title": "Custom Error Classes",
        "body": "export class AppError extends Error {\n  constructor(\n    public message: string,\n    public statusCode: number = 500,\n    public isOperational: boolean = true,\n  ) {\n    super(message);\n    Object.setPrototypeOf(this, AppError.prototype);\n    Error.captureStackTrace(this, this.constructor);\n  }\n}\n\nexport class ValidationError extends AppError {\n  constructor(message: string, public errors?: any[]) { super(message, 400); }\n}\nexport class NotFoundError extends AppError {\n  constructor(message = \"Resource not found\") { super(message, 404); }\n}\nexport class UnauthorizedError extends AppError {\n  constructor(message = \"Unauthorized\") { super(message, 401); }\n}\nexport class ForbiddenError extends AppError {\n  constructor(message = \"Forbidden\") { super(message, 403); }\n}"
      },
      {
        "title": "Global Error Handler",
        "body": "import { Request, Response, NextFunction } from \"express\";\nimport { AppError, ValidationError } from \"../utils/errors\";\n\nexport const errorHandler = (\n  err: Error, req: Request, res: Response, next: NextFunction,\n) => {\n  if (err instanceof AppError) {\n    return res.status(err.statusCode).json({\n      status: \"error\",\n      message: err.message,\n      ...(err instanceof ValidationError && { errors: err.errors }),\n    });\n  }\n\n  // Don't leak details in production\n  const message = process.env.NODE_ENV === \"production\"\n    ? \"Internal server error\"\n    : err.message;\n\n  res.status(500).json({ status: \"error\", message });\n};\n\n// Wrap async route handlers to forward errors\nexport const asyncHandler = (\n  fn: (req: Request, res: Response, next: NextFunction) => Promise<any>,\n) => (req: Request, res: Response, next: NextFunction) => {\n  Promise.resolve(fn(req, res, next)).catch(next);\n};"
      },
      {
        "title": "Validation Middleware (Zod)",
        "body": "import { AnyZodObject, ZodError } from \"zod\";\n\nexport const validate = (schema: AnyZodObject) => {\n  return async (req: Request, res: Response, next: NextFunction) => {\n    try {\n      await schema.parseAsync({\n        body: req.body,\n        query: req.query,\n        params: req.params,\n      });\n      next();\n    } catch (error) {\n      if (error instanceof ZodError) {\n        const errors = error.errors.map((e) => ({\n          field: e.path.join(\".\"),\n          message: e.message,\n        }));\n        next(new ValidationError(\"Validation failed\", errors));\n      } else {\n        next(error);\n      }\n    }\n  };\n};\n\n// Usage\nimport { z } from \"zod\";\nconst createUserSchema = z.object({\n  body: z.object({\n    name: z.string().min(1),\n    email: z.string().email(),\n    password: z.string().min(8),\n  }),\n});\nrouter.post(\"/users\", validate(createUserSchema), userController.createUser);"
      },
      {
        "title": "Auth Middleware",
        "body": "import jwt from \"jsonwebtoken\";\n\ninterface JWTPayload { userId: string; email: string; }\n\nexport const authenticate = async (\n  req: Request, res: Response, next: NextFunction,\n) => {\n  try {\n    const token = req.headers.authorization?.replace(\"Bearer \", \"\");\n    if (!token) throw new UnauthorizedError(\"No token provided\");\n\n    req.user = jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload;\n    next();\n  } catch {\n    next(new UnauthorizedError(\"Invalid token\"));\n  }\n};\n\nexport const authorize = (...roles: string[]) => {\n  return (req: Request, res: Response, next: NextFunction) => {\n    if (!req.user) return next(new UnauthorizedError(\"Not authenticated\"));\n    if (!roles.some((r) => req.user?.roles?.includes(r))) {\n      return next(new ForbiddenError(\"Insufficient permissions\"));\n    }\n    next();\n  };\n};"
      },
      {
        "title": "Auth Service",
        "body": "export class AuthService {\n  constructor(private userRepository: UserRepository) {}\n\n  async login(email: string, password: string) {\n    const user = await this.userRepository.findByEmail(email);\n    if (!user || !(await bcrypt.compare(password, user.password))) {\n      throw new UnauthorizedError(\"Invalid credentials\");\n    }\n\n    return {\n      token: jwt.sign(\n        { userId: user.id, email: user.email },\n        process.env.JWT_SECRET!,\n        { expiresIn: \"15m\" },\n      ),\n      refreshToken: jwt.sign(\n        { userId: user.id },\n        process.env.REFRESH_TOKEN_SECRET!,\n        { expiresIn: \"7d\" },\n      ),\n      user: { id: user.id, name: user.name, email: user.email },\n    };\n  }\n}"
      },
      {
        "title": "PostgreSQL Connection Pool",
        "body": "import { Pool, PoolConfig } from \"pg\";\n\nconst pool = new Pool({\n  host: process.env.DB_HOST,\n  port: parseInt(process.env.DB_PORT || \"5432\"),\n  database: process.env.DB_NAME,\n  user: process.env.DB_USER,\n  password: process.env.DB_PASSWORD,\n  max: 20,\n  idleTimeoutMillis: 30000,\n  connectionTimeoutMillis: 2000,\n});\n\npool.on(\"error\", (err) => {\n  console.error(\"Unexpected database error\", err);\n  process.exit(-1);\n});\n\nexport const closeDatabase = async () => { await pool.end(); };"
      },
      {
        "title": "Transaction Pattern",
        "body": "async createOrder(userId: string, items: OrderItem[]) {\n  const client = await this.db.connect();\n  try {\n    await client.query(\"BEGIN\");\n\n    const { rows } = await client.query(\n      \"INSERT INTO orders (user_id, total) VALUES ($1, $2) RETURNING id\",\n      [userId, calculateTotal(items)],\n    );\n    const orderId = rows[0].id;\n\n    for (const item of items) {\n      await client.query(\n        \"INSERT INTO order_items (order_id, product_id, quantity, price) VALUES ($1, $2, $3, $4)\",\n        [orderId, item.productId, item.quantity, item.price],\n      );\n      await client.query(\n        \"UPDATE products SET stock = stock - $1 WHERE id = $2\",\n        [item.quantity, item.productId],\n      );\n    }\n\n    await client.query(\"COMMIT\");\n    return orderId;\n  } catch (error) {\n    await client.query(\"ROLLBACK\");\n    throw error;\n  } finally {\n    client.release();\n  }\n}"
      },
      {
        "title": "Rate Limiting",
        "body": "import rateLimit from \"express-rate-limit\";\nimport RedisStore from \"rate-limit-redis\";\nimport Redis from \"ioredis\";\n\nconst redis = new Redis({ host: process.env.REDIS_HOST });\n\nexport const apiLimiter = rateLimit({\n  store: new RedisStore({ client: redis, prefix: \"rl:\" }),\n  windowMs: 15 * 60 * 1000,\n  max: 100,\n  standardHeaders: true,\n  legacyHeaders: false,\n});\n\nexport const authLimiter = rateLimit({\n  store: new RedisStore({ client: redis, prefix: \"rl:auth:\" }),\n  windowMs: 15 * 60 * 1000,\n  max: 5,\n  skipSuccessfulRequests: true,\n});"
      },
      {
        "title": "Caching with Redis",
        "body": "import Redis from \"ioredis\";\n\nconst redis = new Redis({\n  host: process.env.REDIS_HOST,\n  retryStrategy: (times) => Math.min(times * 50, 2000),\n});\n\nexport class CacheService {\n  async get<T>(key: string): Promise<T | null> {\n    const data = await redis.get(key);\n    return data ? JSON.parse(data) : null;\n  }\n\n  async set(key: string, value: any, ttl?: number): Promise<void> {\n    const serialized = JSON.stringify(value);\n    ttl ? await redis.setex(key, ttl, serialized) : await redis.set(key, serialized);\n  }\n\n  async delete(key: string): Promise<void> { await redis.del(key); }\n\n  async invalidatePattern(pattern: string): Promise<void> {\n    const keys = await redis.keys(pattern);\n    if (keys.length) await redis.del(...keys);\n  }\n}"
      },
      {
        "title": "API Response Helpers",
        "body": "export class ApiResponse {\n  static success<T>(res: Response, data: T, message?: string, statusCode = 200) {\n    return res.status(statusCode).json({ status: \"success\", message, data });\n  }\n\n  static paginated<T>(res: Response, data: T[], page: number, limit: number, total: number) {\n    return res.json({\n      status: \"success\",\n      data,\n      pagination: { page, limit, total, pages: Math.ceil(total / limit) },\n    });\n  }\n}"
      },
      {
        "title": "Best Practices",
        "body": "Use TypeScript — type safety prevents runtime errors\nValidate all input — Zod or Joi at the middleware layer\nCustom error classes — map to HTTP status codes, use global handler\nNever hardcode secrets — use environment variables\nStructured logging — Pino or Winston with request context\nRate limiting — Redis-backed for distributed deployments\nConnection pooling — always for databases\nDependency injection — constructor injection for testability\nGraceful shutdown — close DB pools, drain connections on SIGTERM\nHealth checks — /health endpoint for liveness/readiness probes"
      }
    ],
    "body": "Node.js Backend Patterns\n\nPatterns for building scalable, maintainable Node.js backend applications with TypeScript.\n\nNEVER\nNEVER store secrets in code - Use environment variables, never hardcode credentials\nNEVER skip input validation - Validate all input at the middleware layer with Zod/Joi\nNEVER expose error details in production - Return generic messages, log details server-side\nNEVER use any type - TypeScript types prevent runtime errors\nNEVER skip error handling - Always wrap async handlers, use global error middleware\nNEVER use sync operations - Use async/await for I/O, never fs.readFileSync in handlers\nNEVER trust client input - Sanitize, validate, and parameterize all queries\nWhen to Use\nBuilding REST APIs with Express or Fastify\nSetting up middleware pipelines and error handling\nImplementing authentication and authorization\nIntegrating databases with connection pooling and transactions\nAdding validation, caching, and rate limiting\nProject Structure — Layered Architecture\nsrc/\n├── controllers/     # Handle HTTP requests/responses\n├── services/        # Business logic\n├── repositories/    # Data access layer\n├── models/          # Data models and types\n├── middleware/      # Auth, validation, logging, errors\n├── routes/          # Route definitions\n├── config/          # Database, cache, env configuration\n└── utils/           # Helpers, custom errors, response formatting\n\n\nControllers handle HTTP concerns, services contain business logic, repositories abstract data access. Each layer only calls the layer below it.\n\nExpress Setup\nimport express from \"express\";\nimport helmet from \"helmet\";\nimport cors from \"cors\";\nimport compression from \"compression\";\n\nconst app = express();\n\napp.use(helmet());\napp.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(\",\") }));\napp.use(compression());\napp.use(express.json({ limit: \"10mb\" }));\napp.use(express.urlencoded({ extended: true, limit: \"10mb\" }));\n\nFastify Setup\nimport Fastify from \"fastify\";\nimport helmet from \"@fastify/helmet\";\nimport cors from \"@fastify/cors\";\n\nconst fastify = Fastify({\n  logger: { level: process.env.LOG_LEVEL || \"info\" },\n});\n\nawait fastify.register(helmet);\nawait fastify.register(cors, { origin: true });\n\n// Type-safe routes with built-in schema validation\nfastify.post<{ Body: { name: string; email: string } }>(\n  \"/users\",\n  {\n    schema: {\n      body: {\n        type: \"object\",\n        required: [\"name\", \"email\"],\n        properties: {\n          name: { type: \"string\", minLength: 1 },\n          email: { type: \"string\", format: \"email\" },\n        },\n      },\n    },\n  },\n  async (request) => {\n    const { name, email } = request.body;\n    return { id: \"123\", name };\n  },\n);\n\nError Handling\nCustom Error Classes\nexport class AppError extends Error {\n  constructor(\n    public message: string,\n    public statusCode: number = 500,\n    public isOperational: boolean = true,\n  ) {\n    super(message);\n    Object.setPrototypeOf(this, AppError.prototype);\n    Error.captureStackTrace(this, this.constructor);\n  }\n}\n\nexport class ValidationError extends AppError {\n  constructor(message: string, public errors?: any[]) { super(message, 400); }\n}\nexport class NotFoundError extends AppError {\n  constructor(message = \"Resource not found\") { super(message, 404); }\n}\nexport class UnauthorizedError extends AppError {\n  constructor(message = \"Unauthorized\") { super(message, 401); }\n}\nexport class ForbiddenError extends AppError {\n  constructor(message = \"Forbidden\") { super(message, 403); }\n}\n\nGlobal Error Handler\nimport { Request, Response, NextFunction } from \"express\";\nimport { AppError, ValidationError } from \"../utils/errors\";\n\nexport const errorHandler = (\n  err: Error, req: Request, res: Response, next: NextFunction,\n) => {\n  if (err instanceof AppError) {\n    return res.status(err.statusCode).json({\n      status: \"error\",\n      message: err.message,\n      ...(err instanceof ValidationError && { errors: err.errors }),\n    });\n  }\n\n  // Don't leak details in production\n  const message = process.env.NODE_ENV === \"production\"\n    ? \"Internal server error\"\n    : err.message;\n\n  res.status(500).json({ status: \"error\", message });\n};\n\n// Wrap async route handlers to forward errors\nexport const asyncHandler = (\n  fn: (req: Request, res: Response, next: NextFunction) => Promise<any>,\n) => (req: Request, res: Response, next: NextFunction) => {\n  Promise.resolve(fn(req, res, next)).catch(next);\n};\n\nValidation Middleware (Zod)\nimport { AnyZodObject, ZodError } from \"zod\";\n\nexport const validate = (schema: AnyZodObject) => {\n  return async (req: Request, res: Response, next: NextFunction) => {\n    try {\n      await schema.parseAsync({\n        body: req.body,\n        query: req.query,\n        params: req.params,\n      });\n      next();\n    } catch (error) {\n      if (error instanceof ZodError) {\n        const errors = error.errors.map((e) => ({\n          field: e.path.join(\".\"),\n          message: e.message,\n        }));\n        next(new ValidationError(\"Validation failed\", errors));\n      } else {\n        next(error);\n      }\n    }\n  };\n};\n\n// Usage\nimport { z } from \"zod\";\nconst createUserSchema = z.object({\n  body: z.object({\n    name: z.string().min(1),\n    email: z.string().email(),\n    password: z.string().min(8),\n  }),\n});\nrouter.post(\"/users\", validate(createUserSchema), userController.createUser);\n\nAuthentication — JWT\nAuth Middleware\nimport jwt from \"jsonwebtoken\";\n\ninterface JWTPayload { userId: string; email: string; }\n\nexport const authenticate = async (\n  req: Request, res: Response, next: NextFunction,\n) => {\n  try {\n    const token = req.headers.authorization?.replace(\"Bearer \", \"\");\n    if (!token) throw new UnauthorizedError(\"No token provided\");\n\n    req.user = jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload;\n    next();\n  } catch {\n    next(new UnauthorizedError(\"Invalid token\"));\n  }\n};\n\nexport const authorize = (...roles: string[]) => {\n  return (req: Request, res: Response, next: NextFunction) => {\n    if (!req.user) return next(new UnauthorizedError(\"Not authenticated\"));\n    if (!roles.some((r) => req.user?.roles?.includes(r))) {\n      return next(new ForbiddenError(\"Insufficient permissions\"));\n    }\n    next();\n  };\n};\n\nAuth Service\nexport class AuthService {\n  constructor(private userRepository: UserRepository) {}\n\n  async login(email: string, password: string) {\n    const user = await this.userRepository.findByEmail(email);\n    if (!user || !(await bcrypt.compare(password, user.password))) {\n      throw new UnauthorizedError(\"Invalid credentials\");\n    }\n\n    return {\n      token: jwt.sign(\n        { userId: user.id, email: user.email },\n        process.env.JWT_SECRET!,\n        { expiresIn: \"15m\" },\n      ),\n      refreshToken: jwt.sign(\n        { userId: user.id },\n        process.env.REFRESH_TOKEN_SECRET!,\n        { expiresIn: \"7d\" },\n      ),\n      user: { id: user.id, name: user.name, email: user.email },\n    };\n  }\n}\n\nDatabase Patterns\nPostgreSQL Connection Pool\nimport { Pool, PoolConfig } from \"pg\";\n\nconst pool = new Pool({\n  host: process.env.DB_HOST,\n  port: parseInt(process.env.DB_PORT || \"5432\"),\n  database: process.env.DB_NAME,\n  user: process.env.DB_USER,\n  password: process.env.DB_PASSWORD,\n  max: 20,\n  idleTimeoutMillis: 30000,\n  connectionTimeoutMillis: 2000,\n});\n\npool.on(\"error\", (err) => {\n  console.error(\"Unexpected database error\", err);\n  process.exit(-1);\n});\n\nexport const closeDatabase = async () => { await pool.end(); };\n\nTransaction Pattern\nasync createOrder(userId: string, items: OrderItem[]) {\n  const client = await this.db.connect();\n  try {\n    await client.query(\"BEGIN\");\n\n    const { rows } = await client.query(\n      \"INSERT INTO orders (user_id, total) VALUES ($1, $2) RETURNING id\",\n      [userId, calculateTotal(items)],\n    );\n    const orderId = rows[0].id;\n\n    for (const item of items) {\n      await client.query(\n        \"INSERT INTO order_items (order_id, product_id, quantity, price) VALUES ($1, $2, $3, $4)\",\n        [orderId, item.productId, item.quantity, item.price],\n      );\n      await client.query(\n        \"UPDATE products SET stock = stock - $1 WHERE id = $2\",\n        [item.quantity, item.productId],\n      );\n    }\n\n    await client.query(\"COMMIT\");\n    return orderId;\n  } catch (error) {\n    await client.query(\"ROLLBACK\");\n    throw error;\n  } finally {\n    client.release();\n  }\n}\n\nRate Limiting\nimport rateLimit from \"express-rate-limit\";\nimport RedisStore from \"rate-limit-redis\";\nimport Redis from \"ioredis\";\n\nconst redis = new Redis({ host: process.env.REDIS_HOST });\n\nexport const apiLimiter = rateLimit({\n  store: new RedisStore({ client: redis, prefix: \"rl:\" }),\n  windowMs: 15 * 60 * 1000,\n  max: 100,\n  standardHeaders: true,\n  legacyHeaders: false,\n});\n\nexport const authLimiter = rateLimit({\n  store: new RedisStore({ client: redis, prefix: \"rl:auth:\" }),\n  windowMs: 15 * 60 * 1000,\n  max: 5,\n  skipSuccessfulRequests: true,\n});\n\nCaching with Redis\nimport Redis from \"ioredis\";\n\nconst redis = new Redis({\n  host: process.env.REDIS_HOST,\n  retryStrategy: (times) => Math.min(times * 50, 2000),\n});\n\nexport class CacheService {\n  async get<T>(key: string): Promise<T | null> {\n    const data = await redis.get(key);\n    return data ? JSON.parse(data) : null;\n  }\n\n  async set(key: string, value: any, ttl?: number): Promise<void> {\n    const serialized = JSON.stringify(value);\n    ttl ? await redis.setex(key, ttl, serialized) : await redis.set(key, serialized);\n  }\n\n  async delete(key: string): Promise<void> { await redis.del(key); }\n\n  async invalidatePattern(pattern: string): Promise<void> {\n    const keys = await redis.keys(pattern);\n    if (keys.length) await redis.del(...keys);\n  }\n}\n\nAPI Response Helpers\nexport class ApiResponse {\n  static success<T>(res: Response, data: T, message?: string, statusCode = 200) {\n    return res.status(statusCode).json({ status: \"success\", message, data });\n  }\n\n  static paginated<T>(res: Response, data: T[], page: number, limit: number, total: number) {\n    return res.json({\n      status: \"success\",\n      data,\n      pagination: { page, limit, total, pages: Math.ceil(total / limit) },\n    });\n  }\n}\n\nBest Practices\nUse TypeScript — type safety prevents runtime errors\nValidate all input — Zod or Joi at the middleware layer\nCustom error classes — map to HTTP status codes, use global handler\nNever hardcode secrets — use environment variables\nStructured logging — Pino or Winston with request context\nRate limiting — Redis-backed for distributed deployments\nConnection pooling — always for databases\nDependency injection — constructor injection for testability\nGraceful shutdown — close DB pools, drain connections on SIGTERM\nHealth checks — /health endpoint for liveness/readiness probes"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/wpank/nodejs-patterns",
    "publisherUrl": "https://clawhub.ai/wpank/nodejs-patterns",
    "owner": "wpank",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/nodejs-patterns",
    "downloadUrl": "https://openagent3.xyz/downloads/nodejs-patterns",
    "agentUrl": "https://openagent3.xyz/skills/nodejs-patterns/agent",
    "manifestUrl": "https://openagent3.xyz/skills/nodejs-patterns/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/nodejs-patterns/agent.md"
  }
}