Table Of Contents
Problem
You need to create routes that work with optional parameters, like /users
and /users/123
, or /search
and /search/category/electronics
without duplicating route definitions.
Solution
const express = require('express');
const app = express();
// Method 1: Optional parameter with ?
app.get('/users/:id?', (req, res) => {
const userId = req.params.id;
if (userId) {
// GET /users/123
res.json({
message: `User details for ID: ${userId}`,
user: { id: userId, name: 'John Doe' }
});
} else {
// GET /users
res.json({
message: 'All users',
users: [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
]
});
}
});
// Method 2: Multiple optional parameters
app.get('/search/:query?/:category?', (req, res) => {
const { query, category } = req.params;
let result = {
query: query || 'all',
category: category || 'general',
results: []
};
if (query && category) {
// GET /search/laptop/electronics
result.results = [`${query} in ${category}`];
} else if (query) {
// GET /search/laptop
result.results = [`${query} in all categories`];
} else {
// GET /search
result.results = ['All items'];
}
res.json(result);
});
// Method 3: Using regex for complex optional patterns
app.get(/^\/products\/?(\d+)?\/?$/, (req, res) => {
const productId = req.params[0]; // First capture group
if (productId) {
res.json({
message: `Product ${productId}`,
product: { id: productId, name: 'Sample Product' }
});
} else {
res.json({
message: 'All products',
products: ['Product 1', 'Product 2']
});
}
});
// Method 4: Separate routes with shared logic
const handleArticles = (req, res) => {
const { category, slug } = req.params;
if (category && slug) {
res.json({
type: 'specific article',
category,
slug,
article: `Article: ${slug} in ${category}`
});
} else if (category) {
res.json({
type: 'category articles',
category,
articles: [`Articles in ${category}`]
});
} else {
res.json({
type: 'all articles',
articles: ['All articles']
});
}
};
app.get('/articles', handleArticles);
app.get('/articles/:category', handleArticles);
app.get('/articles/:category/:slug', handleArticles);
// Method 5: Using query parameters as alternative
app.get('/api/posts', (req, res) => {
const { category, author, limit = 10 } = req.query;
let filters = {};
if (category) filters.category = category;
if (author) filters.author = author;
res.json({
message: 'Posts with optional filters',
filters,
limit: parseInt(limit),
posts: ['Post 1', 'Post 2']
});
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
Example requests:
# Optional parameter routes
curl http://localhost:3000/users # All users
curl http://localhost:3000/users/123 # Specific user
# Multiple optional parameters
curl http://localhost:3000/search # All items
curl http://localhost:3000/search/laptop # Search laptop
curl http://localhost:3000/search/laptop/electronics # Search in category
# Query parameters
curl "http://localhost:3000/api/posts?category=tech&author=john&limit=5"
Explanation
Adding ?
after a parameter name makes it optional (:id?
). The parameter will be undefined
if not provided. For multiple optional parameters, each gets its own ?
.
Regex routes offer more control but are harder to read. Query parameters (?category=tech
) are often better for optional filters since they're more flexible and don't require specific URL patterns. Choose the method that best fits your API design and user experience needs.
Share this article
Add Comment
No comments yet. Be the first to comment!