# Nodejs Express

> Node.js + Express backend patterns. Use when building REST APIs, middleware, authentication, or backend services with Node.js/Express/TypeScript. Use when this capability is needed.

- Skill: `tomevault-io/nodejs-express` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/nodejs-express`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/nodejs-express/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/nodejs-express

---


# Node.js + Express Patterns

## Project Structure
```
src/
  app.ts           # Express app, middleware setup
  server.ts        # HTTP server, port binding
  routes/          # Route definitions (auth.ts, users.ts)
  controllers/     # Request handlers
  services/        # Business logic
  models/          # Prisma/Mongoose models
  middleware/      # auth, error, validation
  types/           # TypeScript interfaces
  utils/           # Helpers
```

## App Setup
```typescript
// app.ts
import express from 'express'
import helmet from 'helmet'
import cors from 'cors'
import { errorHandler } from './middleware/error'

const app = express()

app.use(helmet())
app.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(','), credentials: true }))
app.use(express.json({ limit: '1mb' }))
app.use(express.urlencoded({ extended: true }))

app.use('/api/auth', authRouter)
app.use('/api/users', authenticate, usersRouter)

app.get('/health', (req, res) => res.json({ status: 'ok' }))

app.use(errorHandler)  // Must be last
export default app
```

## Controller Pattern (async error handling)
```typescript
// Wrap async handlers to catch errors automatically
const asyncHandler = (fn: RequestHandler): RequestHandler =>
  (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next)

export const getUser = asyncHandler(async (req, res) => {
  const user = await userService.findById(Number(req.params.id))
  if (!user) return res.status(404).json({ error: 'User not found' })
  res.json(user)
})
```

## Auth Middleware
```typescript
import jwt from 'jsonwebtoken'

export const authenticate: RequestHandler = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1]
  if (!token) return res.status(401).json({ error: 'No token' })
  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET!) as JwtPayload
    req.user = payload
    next()
  } catch {
    res.status(401).json({ error: 'Invalid token' })
  }
}
```

## Validation Middleware (Zod)
```typescript
import { z } from 'zod'

const validate = (schema: z.ZodSchema) => (req: Request, res: Response, next: NextFunction) => {
  const result = schema.safeParse(req.body)
  if (!result.success) return res.status(400).json({ errors: result.error.flatten() })
  req.body = result.data
  next()
}

const CreateUserSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
  name: z.string().max(100)
})

router.post('/users', validate(CreateUserSchema), createUser)
```

## Error Handler
```typescript
export const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
  console.error(err)
  const status = err.status || 500
  const message = status < 500 ? err.message : 'Internal server error'
  res.status(status).json({ error: message })
}
```

## Rules
- Use `helmet()` for security headers
- Use `express-rate-limit` on auth endpoints
- Validate ALL input with Zod (never trust req.body directly)
- Wrap all async handlers in asyncHandler (never unhandled promise rejections)
- Keep controllers thin — business logic in services
- Use `process.env` for config, validate at startup (crash fast if missing)
- Return 404 for missing resources, 400 for bad input, 401/403 for auth, 500 for server errors

---
> Source: [cohen-liel/hivemind](https://github.com/cohen-liel/hivemind) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-05-22 -->

