From harness-claude
Structures Express applications with middleware chains, routers, async error handling, request validation, and proper middleware ordering for REST APIs.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:node-express-patternsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Structure Express applications with middleware chains, routers, and proper error handling
Structure Express applications with middleware chains, routers, and proper error handling
import express from 'express';
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// routes/users.ts
import { Router } from 'express';
const router = Router();
router.get('/', async (req, res) => {
const users = await userService.findAll();
res.json(users);
});
router.get('/:id', async (req, res) => {
const user = await userService.findById(req.params.id);
if (!user) return res.status(404).json({ error: 'User not found' });
res.json(user);
});
router.post('/', async (req, res) => {
const user = await userService.create(req.body);
res.status(201).json(user);
});
export { router as userRouter };
// app.ts
app.use('/api/users', userRouter);
type AsyncHandler = (req: Request, res: Response, next: NextFunction) => Promise<void>;
function asyncHandler(fn: AsyncHandler) {
return (req: Request, res: Response, next: NextFunction) => {
fn(req, res, next).catch(next);
};
}
router.get(
'/:id',
asyncHandler(async (req, res) => {
const user = await userService.findById(req.params.id);
if (!user) throw new NotFoundError('User', req.params.id);
res.json(user);
})
);
// 1. Parsing (runs first)
app.use(express.json());
// 2. Logging
app.use(requestLogger);
// 3. Authentication
app.use('/api', authenticate);
// 4. Routes
app.use('/api/users', userRouter);
app.use('/api/posts', postRouter);
// 5. 404 handler (after all routes)
app.use((req, res) => res.status(404).json({ error: 'Not found' }));
// 6. Error handler (must have 4 parameters)
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
});
import { z, ZodSchema } from 'zod';
function validate(schema: ZodSchema) {
return (req: Request, res: Response, next: NextFunction) => {
const result = schema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ errors: result.error.flatten().fieldErrors });
}
req.body = result.data;
next();
};
}
const CreateUserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
});
router.post(
'/',
validate(CreateUserSchema),
asyncHandler(async (req, res) => {
const user = await userService.create(req.body); // req.body is validated
res.status(201).json(user);
})
);
async function authenticate(req: Request, res: Response, next: NextFunction) {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) return res.status(401).json({ error: 'No token provided' });
try {
const payload = await verifyToken(token);
req.userId = payload.userId;
next();
} catch {
res.status(401).json({ error: 'Invalid token' });
}
}
const server = app.listen(3000);
process.on('SIGTERM', () => {
server.close(() => process.exit(0));
});
Express uses a middleware chain pattern where each middleware receives (req, res, next) and either responds or calls next() to pass control to the next middleware.
Error handling middleware must have exactly 4 parameters (err, req, res, next). Express identifies error handlers by their arity. Place them after all routes.
Express 5 (beta): Automatically catches async errors without the asyncHandler wrapper. Until Express 5 is stable, the wrapper is required.
Trade-offs:
https://expressjs.com/en/guide/routing.html
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeGenerates Express.js REST APIs with TypeScript, middleware, validation, error handling, and authentication patterns.
Builds Express.js servers with middleware, authentication, routing, and database integration for REST APIs.
Implements Node.js backend patterns with Express/Fastify for middleware, error handling, auth, DB integration, REST/GraphQL APIs, microservices, and WebSockets.