expressjs-development
Comprehensive Express.js development skill covering routing, middleware, request/response handling, error handling, and building production-ready REST APIs
- Category: discovered
- Tags: github, community
- Version: 1.0.0
- Author: walid
- Downloads: 0
- Updated: 2025-11-22
Download the latest version (v1.0.0) from this page.
SKILL.md
---
name: expressjs-development
description: Comprehensive Express.js development skill covering routing, middleware, request/response handling, error handling, and building production-ready REST APIs
category: backend
tags: [expressjs, nodejs, rest-api, middleware, routing, backend, web-server]
version: 1.0.0
context7_library: /expressjs/express
context7_trust_score: 9
---
# Express.js Development Skill
This skill provides comprehensive guidance for building production-ready web applications and REST APIs using Express.js, covering routing, middleware, request/response handling, error handling, authentication, validation, and deployment best practices.
## When to Use This Skill
Use this skill when:
- Building RESTful APIs for web and mobile applications
- Creating backend services and microservices
- Developing web servers with server-side rendering
- Implementing API gateways and proxy servers
- Building real-time applications with WebSocket support
- Creating middleware-based request processing pipelines
- Developing authentication and authorization systems
- Implementing file upload and download services
- Building webhook handlers and integrations
- Creating serverless functions with Express
## Core Concepts
### Application Setup
Express applications are built by creating an instance of Express and configuring middleware and routes.
**Basic Express Application:**
```javascript
const express = require('express');
const app = express();
// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Routes
app.get('/', (req, res) => {
res.send('Hello World!');
});
// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
```
**Application with Configuration:**
```javascript
const express = require('express');
const app = express();
// App settings
app.set('port', process.env.PORT || 3000);
app.set('env', process.env.NODE_ENV || 'development');
app.set('trust proxy', 1); // Trust first proxy
// View engine setup (optional)
app.set('view engine', 'ejs');
app.set('views', './views');
// Static files
app.use(express.static('public'));
// Body parsing
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
module.exports = app;
```
### Routing
Routing refers to how an application's endpoints (URIs) respond to client requests.
**Basic Routes:**
```javascript
const express = require('express');
const app = express();
// HTTP Methods
app.get('/users', (req, res) => {
res.json({ message: 'Get all users' });
});
app.post('/users', (req, res) => {
res.json({ message: 'Create user' });
});
app.put('/users/:id', (req, res) => {
res.json({ message: `Update user ${req.params.id}` });
});
app.delete('/users/:id', (req, res) => {
res.json({ message: `Delete user ${req.params.id}` });
});
// Multiple methods on same route
app.route('/users/:id')
.get((req, res) => res.json({ message: 'Get user' }))
.put((req, res) => res.json({ message: 'Update user' }))
.delete((req, res) => res.json({ message: 'Delete user' }));
```
**Route Parameters:**
```javascript
// Single parameter
app.get('/users/:userId', (req, res) => {
const { userId } = req.params;
res.json({ userId });
});
// Multiple parameters
app.get('/users/:userId/posts/:postId', (req, res) => {
const { userId, postId } = req.params;
res.json({ userId, postId });
});
// Optional parameters with regex
app.get('/users/:userId/posts/:postId?', (req, res) => {
// postId is optional
res.json(req.params);
});
// Parameter validation
app.param('userId', (req, res, next, id) => {
// Validate or transform parameter
if (!id.match(/^\d+$/)) {
return res.status(400).json({ error: 'Invalid user ID' });
}
req.userId = parseInt(id);
next();
});
```
**Query Strings:**
```javascript
// GET /search?q=express&limit=10&page=2
app.get('/search', (req, res) => {
const { q, limit = 20, page = 1 } = req.query;
res.json({
query: q,
limit: parseInt(limit),
page: parseInt(page)
});
});
```
**Router Modules:**
```javascript
// routes/users.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.json({ message: 'Get all users' });
});
router.get('/:id', (req, res) => {
res.json({ message: `Get user ${req.params.id}` });
});
router.post('/', (req, res) => {
res.json({ message: 'Create user' });
});
module.exports = router;
// app.js
const usersRouter = require('./routes/users');
app.use('/api/users', usersRouter);
```
### Middleware
Middleware functions have access to the request object (req), the response object (res), and the next middleware function in the application's request-response cycle.
**Application-Level Middleware:**
```javascript
// Executed for every request
app.use((req, res, next) => {
console.log(`${req.method} ${req.path}`);
next();
});
// Executed for specific path
app.use('/api', (req, res, next) => {
req.startTime = Date.now();
next();
});
// Multiple middleware functions
app.use(
express.json(),
express.urlencoded({ extended: true }),
cookieParser()
);
```
**Router-Level Middleware:**
```javascript
const router = express.Router();
// Middleware for all routes in this router
router.use((req, res, next) => {
console.log('Router middleware');
next();
});
// Middleware for specific route
router.get('/users',
authMiddleware,
validationMiddleware,
(req, res) => {
res.json({ users: [] });
}
);
```
**Built-in Middleware:**
```javascript
// Parse JSON bodies
app.use(express.json());
// Parse URL-encoded bodies
app.use(express.urlencoded({ extended: true }));
// Serve static files
app.use(express.static('public'));
app.use('/uploads', express.static('uploads'));
```
**Third-Party Middleware:**
```javascript
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const compression = require('compression');
// Security headers
app.use(helmet());
// CORS
app.use(cors({
origin: 'https://example.com',
credentials: true
}));
// Logging
app.use(morgan('combined'));
// Compression
app.use(compression());
```
**Custom Middleware:**
```javascript
// Request logging middleware
function requestLogger(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
function requireAuth(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
res.status(401).json({ error: 'Invalid token' });
}
}
// Request validation middleware
function validateUser(req, res, next) {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).json({
error: 'Email and password are required'
});
}
if (!email.includes('@')) {
return res.status(400).json({ error: 'Invalid email' });
}
next();
}
app.use(requestLogger);
app.post('/login', validateUser, loginHandler);
app.get('/protected', requireAuth, protectedHandler);
```
### Request Object
The request object represents the HTTP request and has properties for query strings, parameters, body, headers, etc.
**Request Properties:**
```javascript
app.post('/api/users/:id', (req, res) => {
// Route parameters
const { id } = req.params;
// Query string
const { sort, filter } = req.query;
// Request body
const { name, email } = req.body;
// Headers
const userAgent = req.get('User-Agent');
const contentType = req.get('Content-Type');
// Request info
const method = req.method;
const path = req.path;
const url = req.url;
const baseUrl = req.baseUrl;
const protocol = req.protocol;
const hostname = req.hostname;
const ip = req.ip;
// Cookies (requires cookie-parser)
const { sessionId } = req.cookies;
res.json({ id, name, email });
});
```
**Request Methods:**
```javascript
app.post('/upload', (req, res) => {
// Check content type
if (req.is('application/json')) {
// Handle JSON
}
// Check accept header
if (req.accepts('json')) {
res.json({ data: 'json response' });
} else if (req.accepts('html')) {
res.send('<html>html response</html>');
}
// Get header value
const auth = req.get('Authorization');
// Get range header
const range = req.range(1000);
});
```
### Response Object
The response object represents the HTTP response that an Express app sends when it gets an HTTP request.
**Sending Responses:**
```javascript
app.get('/api/data', (req, res) => {
// Send JSON
res.json({ message: 'Success', data: [] });
// Send string
res.send('Hello World');
// Send status
res.sendStatus(200); // Equivalent to res.status(200).send('OK')
// Send file
res.sendFile('/path/to/file.pdf');
// Download file
res.download('/path/to/file.pdf', 'document.pdf');
// Render view
res.render('index', { title: 'Home' });
// Redirect
res.redirect('/login');
res.redirect(301, 'https://example.com');
// End response
res.end();
});
```
**Setting Status and Headers:**
```javascript
app.get('/api/resource', (req, res) => {
// Set status code
res.status(201).json({ created: true });
// Set headers
res.set('Content-Type', 'application/json');
res.set({
'X-API-Version': '1.0',
'X-Rate-Limit': '100'
});
// Set cookie
res.cookie('name', 'value', {
maxAge: 900000,
httpOnly: true,
secure: true,
sameSite: 'strict'
});
// Clear cookie
res.clearCookie('name');
res.json({ success: true });
});
```
**Response Formats:**
```javascript
app.get('/api/users/:id', (req, res) => {
const user = { id: 1, name: 'John' };
res.format({
'text/plain': () => {
res.send(`${user.name}`);
},
'text/html': () => {
res.send(`<p>${user.name}</p>`);
},
'application/json': () => {
res.json(user);
},
default: () => {
res.status(406).send('Not Acceptable');
}
});
});
```
### Error Handling
Error-handling middleware functions have four arguments: (err, req, res, next).
**Error-Handling Middleware:**
```javascript
// 404 handler
app.use((req, res, next) => {
res.status(404).json({ error: 'Not found' });
});
// Error handler (must be last)
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(err.status || 500).json({
error: {
message: err.message,
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
}
});
});
```
**Async Error Handling:**
```javascript
// Async wrapper utility
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
// Using async wrapper
app.get('/api/users/:id', asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);
if (!user) {
const error = new Error('User not found');
error.status = 404;
throw error;
}
res.json(user);
}));
// Custom error classes
class AppError extends Error {
constructor(message, status) {
super(message);
this.status = status;
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
class NotFoundError extends AppError {
constructor(message = 'Resource not found') {
super(message, 404);
}
}
class ValidationError extends AppError {
constructor(message = 'Validation failed') {
super(message, 400);
}
}
```
## API Reference
### Express Application Methods
**app.use([path], middleware)**
- Mounts middleware at the specified path
- If path is not specified, middleware is executed for every request
**app.METHOD(path, [middleware...], handler)**
- Routes HTTP requests (GET, POST, PUT, DELETE, etc.)
- Multiple middleware functions can be specified
**app.route(path)**
- Returns an instance of a single route for chaining HTTP verbs
**app.listen(port, [hostname], [backlog], [callback])**
- Binds and listens for connections on the specified host and port
**app.param(name, callback)**
- Adds callback triggers to route parameters
**app.set(name, value)**
- Assigns setting name to value
**app.get(name)**
- Returns the value of setting name
### Router Methods
**router.use([path], middleware)**
- Mounts middleware for the router
**router.METHOD(path, [middleware...], handler)**
- Routes HTTP requests within the router
**router.route(path)**
- Returns a route instance for chaining
**router.param(name, callback)**
- Adds parameter callbacks
### Request Properties
- **req.body**: Contains parsed request body (requires body-parser)
- **req.params**: Route parameters
- **req.query**: Parsed query string
- **req.headers**: Request headers
- **req.cookies**: Cookies (requires cookie-parser)
- **req.method**: HTTP method
- **req.path**: Request path
- **req.url**: Full URL
- **req.ip**: Remote IP address
- **req.protocol**: Request protocol (http or https)
### Request Methods
- **req.get(header)**: Returns header value
- **req.is(type)**: Checks if content type matches
- **req.accepts(types)**: Checks if types are acceptable
- **req.range(size)**: Parses range header
### Response Methods
- **res.json(obj)**: Sends JSON response
- **res.send(body)**: Sends response
- **res.status(code)**: Sets status code
- **res.sendStatus(code)**: Sets status and sends status message
- **res.set(field, value)**: Sets response header
- **res.cookie(name, value, options)**: Sets cookie
- **res.clearCookie(name)**: Clears cookie
- **res.redirect([status], path)**: Redirects to path
- **res.render(view, locals)**: Renders view template
- **res.sendFile(path)**: Sends file
- **res.download(path, filename)**: Downloads file
## Workflow Patterns
### REST API Design
**Complete REST API Example:**
```javascript
const express = require('express');
const router = express.Router();
// GET /api/users - List all users
router.get('/', asyncHandler(async (req, res) => {
const { page = 1, limit = 10, sort = 'createdAt' } = req.query;
const users = await User.find()
.sort(sort)
.limit(parseInt(limit))
.skip((parseInt(page) - 1) * parseInt(limit))
.select('-password');
const total = await User.countDocuments();
res.json({
data: users,
pagination: {
page: parseInt(page),
limit: parseInt(limit),
total,
pages: Math.ceil(total / limit)
}
});
}));
// GET /api/users/:id - Get single user
router.get('/:id', asyncHandler(async (req, res) => {
const user = await User.findById(req.params.id).select('-password');
if (!user) {
throw new NotFoundError('User not found');
}
res.json({ data: user });
}));
// POST /api/users - Create user
router.post('/',
validateUser,
asyncHandler(async (req, res) => {
const { email, password, name } = req.body;
const existingUser = await User.findOne({ email });
if (existingUser) {
throw new ValidationError('Email already exists');
}
const user = await User.create({ email, password, name });
res.status(201).json({
data: user.toJSON(),
message: 'User created successfully'
});
})
);
// PUT /api/users/:id - Update user
router.put('/:id',
requireAuth,
validateUserUpdate,
asyncHandler(async (req, res) => {
const user = await User.findByIdAndUpdate(
req.params.id,
req.body,
{ new: true, runValidators: true }
).select('-password');
if (!user) {
throw new NotFoundError('User not found');
}
res.json({
data: user,
message: 'User updated successfully'
});
})
);
// DELETE /api/users/:id - Delete user
router.delete('/:id',
requireAuth,
asyncHandler(async (req, res) => {
const user = await User.findByIdAndDelete(req.params.id);
if (!user) {
throw new NotFoundError('User not found');
}
res.json({ message: 'User deleted successfully' });
})
);
module.exports = router;
```
### Authentication
**JWT Authentication:**
```javascript
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
// Register
router.post('/register',
validateRegistration,
asyncHandler(async (req, res) => {
const { email, password, name } = req.body;
// Check if user exists
const existingUser = await User.findOne({ email });
if (existingUser) {
throw new ValidationError('Email already registered');
}
// Hash password
const hashedPassword = await bcrypt.hash(password, 10);
// Create user
const user = await User.create({
email,
password: hashedPassword,
name
});
// Generate token
const token = jwt.sign(
{ userId: user._id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
res.status(201).json({
data: {
user: user.toJSON(),
token
}
});
})
);
// Login
router.post('/login',
validateLogin,
asyncHandler(async (req, res) => {
const { email, password } = req.body;
// Find user
const user = await User.findOne({ email });
if (!user) {
throw new ValidationError('Invalid credentials');
}
// Verify password
const isValid = await bcrypt.compare(password, user.password);
if (!isValid) {
throw new ValidationError('Invalid credentials');
}
// Generate token
const token = jwt.sign(
{ userId: user._id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
res.json({
data: {
user: user.toJSON(),
token
}
});
})
);
// Refresh token
router.post('/refresh',
asyncHandler(async (req, res) => {
const { refreshToken } = req.body;
if (!refreshToken) {
throw new ValidationError('Refresh token required');
}
const decoded = jwt.verify(refreshToken, process.env.REFRESH_SECRET);
const token = jwt.sign(
{ userId: decoded.userId, email: decoded.email },
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
res.json({ data: { token } });
})
);
// Auth middleware
function requireAuth(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
throw new AuthenticationError('No token provided');
}
const token = authHeader.split(' ')[1];
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
throw new AuthenticationError('Invalid token');
}
}
// Role-based authorization
function requireRole(...roles) {
return async (req, res, next) => {
const user = await User.findById(req.user.userId);
if (!user || !roles.includes(user.role)) {
throw new ForbiddenError('Insufficient permissions');
}
next();
};
}
```
### Validation
**Input Validation with express-validator:**
```javascript
const { body, param, query, validationResult } = require('express-validator');
// Validation middleware
const validate = (validations) => {
return async (req, res, next) => {
await Promise.all(validations.map(validation => validation.run(req)));
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
error: 'Validation failed',
details: errors.array()
});
}
next();
};
};
// User validation rules
const userValidationRules = {
create: validate([
body('email')
.isEmail()
.normalizeEmail()
.withMessage('Invalid email address'),
body('password')
.isLength({ min: 8 })
.withMessage('Password must be at least 8 characters')
.matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/)
.withMessage('Password must contain uppercase, lowercase, and number'),
body('n