home / skills / aj-geddes / useful-ai-prompts / nodejs-express-server
This skill helps you design production-ready Node.js Express servers with routing, middleware, authentication, and database integration.
npx playbooks add skill aj-geddes/useful-ai-prompts --skill nodejs-express-serverReview the files below or copy the command above to add this skill to your agents.
---
name: nodejs-express-server
description: Build production-ready Express.js servers with middleware, authentication, routing, and database integration. Use when creating REST APIs, managing requests/responses, implementing middleware chains, and handling server logic.
---
# Node.js Express Server
## Overview
Create robust Express.js applications with proper routing, middleware chains, authentication mechanisms, and database integration following industry best practices.
## When to Use
- Building REST APIs with Node.js
- Implementing server-side request handling
- Creating middleware chains for cross-cutting concerns
- Managing authentication and authorization
- Connecting to databases from Node.js
- Implementing error handling and logging
## Instructions
### 1. **Basic Express Setup**
```javascript
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Routes
app.get('/health', (req, res) => {
res.json({ status: 'OK', timestamp: new Date().toISOString() });
});
// Error handling
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(err.status || 500).json({
error: err.message,
requestId: req.id
});
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
```
### 2. **Middleware Chain Implementation**
```javascript
// Logging middleware
const logger = (req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`${req.method} ${req.path} ${res.statusCode} ${duration}ms`);
});
next();
};
// Authentication middleware
const authenticateToken = (req, res, next) => {
const token = req.headers['authorization']?.split(' ')[1];
if (!token) return res.status(401).json({ error: 'No token' });
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.status(403).json({ error: 'Invalid token' });
req.user = user;
next();
});
};
// Error catching middleware wrapper
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
app.use(logger);
app.use(express.json());
app.get('/protected', authenticateToken, (req, res) => {
res.json({ user: req.user });
});
```
### 3. **Database Integration (PostgreSQL with Sequelize)**
```javascript
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize(
process.env.DB_NAME,
process.env.DB_USER,
process.env.DB_PASS,
{
host: process.env.DB_HOST,
dialect: 'postgres',
logging: false
}
);
const User = sequelize.define('User', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
},
email: {
type: DataTypes.STRING,
unique: true,
allowNull: false
},
password: DataTypes.STRING,
role: {
type: DataTypes.ENUM('user', 'admin'),
defaultValue: 'user'
}
}, {
timestamps: true
});
// Sync database
sequelize.sync({ alter: true });
```
### 4. **Authentication with JWT**
```javascript
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const generateToken = (userId) => {
return jwt.sign(
{ userId, iat: Math.floor(Date.now() / 1000) },
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
};
app.post('/login', asyncHandler(async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ where: { email } });
if (!user) return res.status(404).json({ error: 'User not found' });
const validPassword = await bcrypt.compare(password, user.password);
if (!validPassword) return res.status(401).json({ error: 'Invalid password' });
const token = generateToken(user.id);
res.json({ token, user: { id: user.id, email: user.email } });
}));
```
### 5. **RESTful Routes with CRUD Operations**
```javascript
const userRouter = express.Router();
// GET all users (with pagination)
userRouter.get('/', authenticateToken, asyncHandler(async (req, res) => {
const { page = 1, limit = 20 } = req.query;
const users = await User.findAndCountAll({
offset: (page - 1) * limit,
limit: parseInt(limit)
});
res.json({
data: users.rows,
pagination: { page, limit, total: users.count }
});
}));
// GET single user
userRouter.get('/:id', authenticateToken, asyncHandler(async (req, res) => {
const user = await User.findByPk(req.params.id);
if (!user) return res.status(404).json({ error: 'Not found' });
res.json({ data: user });
}));
// POST create user
userRouter.post('/', asyncHandler(async (req, res) => {
const { email, password } = req.body;
const hashedPassword = await bcrypt.hash(password, 10);
const user = await User.create({
email,
password: hashedPassword
});
res.status(201).json({ data: user });
}));
// PATCH update user
userRouter.patch('/:id', authenticateToken, asyncHandler(async (req, res) => {
const user = await User.findByPk(req.params.id);
if (!user) return res.status(404).json({ error: 'Not found' });
await user.update(req.body, {
fields: ['email', 'role']
});
res.json({ data: user });
}));
// DELETE user
userRouter.delete('/:id', authenticateToken, asyncHandler(async (req, res) => {
const user = await User.findByPk(req.params.id);
if (!user) return res.status(404).json({ error: 'Not found' });
await user.destroy();
res.status(204).send();
}));
app.use('/api/users', userRouter);
```
### 6. **Error Handling Middleware**
```javascript
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
Error.captureStackTrace(this, this.constructor);
}
}
app.use((err, req, res, next) => {
err.statusCode = err.statusCode || 500;
if (err.name === 'SequelizeValidationError') {
return res.status(400).json({
error: 'Validation failed',
details: err.errors.map(e => ({ field: e.path, message: e.message }))
});
}
if (process.env.NODE_ENV === 'production') {
return res.status(err.statusCode).json({
error: err.message,
requestId: req.id
});
}
res.status(err.statusCode).json({
error: err.message,
stack: err.stack
});
});
app.use((req, res) => {
res.status(404).json({ error: 'Route not found' });
});
```
### 7. **Environment Configuration**
```javascript
require('dotenv').config();
const config = {
port: process.env.PORT || 3000,
env: process.env.NODE_ENV || 'development',
database: {
url: process.env.DATABASE_URL,
dialect: 'postgres'
},
jwt: {
secret: process.env.JWT_SECRET,
expiresIn: '24h'
},
cors: {
origin: process.env.CORS_ORIGIN || 'http://localhost:3000'
}
};
module.exports = config;
```
## Best Practices
### ✅ DO
- Use middleware for cross-cutting concerns
- Implement proper error handling
- Validate input data before processing
- Use async/await for async operations
- Implement authentication on protected routes
- Use environment variables for configuration
- Add logging and monitoring
- Use HTTPS in production
- Implement rate limiting
- Keep route handlers focused and small
### ❌ DON'T
- Handle errors silently
- Store sensitive data in code
- Use synchronous operations in routes
- Forget to validate user input
- Implement authentication in route handlers
- Use callback hell (use promises/async-await)
- Expose stack traces in production
- Trust client-side validation only
## Complete Example
```javascript
const express = require('express');
const jwt = require('jsonwebtoken');
const { Sequelize, DataTypes } = require('sequelize');
const app = express();
app.use(express.json());
const sequelize = new Sequelize('postgres://user:pass@localhost/db');
const User = sequelize.define('User', {
email: DataTypes.STRING,
password: DataTypes.STRING
});
const authenticateToken = (req, res, next) => {
const token = req.headers['authorization']?.split(' ')[1];
jwt.verify(token, 'secret', (err, user) => {
if (err) return res.status(403).json({ error: 'Forbidden' });
req.user = user;
next();
});
};
app.get('/users', authenticateToken, async (req, res, next) => {
try {
const users = await User.findAll();
res.json({ data: users });
} catch (err) {
next(err);
}
});
app.post('/users', async (req, res, next) => {
try {
const user = await User.create(req.body);
res.status(201).json({ data: user });
} catch (err) {
next(err);
}
});
app.listen(3000, () => console.log('Server running on port 3000'));
```
This skill builds production-ready Node.js servers using Express.js with routing, middleware, authentication, and database integration. It provides patterns for clean request handling, error management, and secure JWT-based authentication. The goal is to help you scaffold maintainable REST APIs that follow industry best practices.
The skill sets up Express middleware chains (logging, parsing, auth), async error handling wrappers, and structured route modules. It integrates Sequelize for PostgreSQL, defines models, and syncs schemas. Authentication is handled with bcrypt for passwords and JWT for session tokens. Centralized error middleware and environment-driven configuration secure and standardize runtime behavior.
How do I secure JWT secrets and database credentials?
Keep them in environment variables, use a secrets manager in production, and avoid committing them to source control.
What if my async route throws an error?
Wrap async handlers with an async handler helper so thrown errors are forwarded to centralized error middleware.