Skip to main content

Express Code Quality

Writing high-quality code is essential for creating maintainable, scalable, and robust Express.js applications. In this guide, we'll explore the key practices and tools that help ensure your Express code remains clean, efficient, and professional.

Why Code Quality Matters

When building Express applications, code quality affects:

  • Maintainability: How easily can you or others modify the code later?
  • Scalability: How well will the application handle growth?
  • Reliability: How dependably will the application run without failures?
  • Team Collaboration: How effectively can multiple developers work together?

Essential Code Quality Tools

Linting with ESLint

Linting automatically checks your code for potential errors and enforces consistent style.

Setting up ESLint for Express

  1. Install ESLint and the Express plugin:
bash
npm install eslint eslint-plugin-node --save-dev
  1. Create a configuration file (.eslintrc.js):
javascript
module.exports = {
env: {
node: true,
es6: true
},
extends: [
'eslint:recommended',
'plugin:node/recommended'
],
rules: {
'no-console': 'warn',
'node/exports-style': ['error', 'module.exports'],
'node/no-unsupported-features/es-syntax': [
'error',
{ ignores: ['modules'] }
]
}
};
  1. Add a lint script to your package.json:
json
{
"scripts": {
"lint": "eslint ."
}
}

Code Formatting with Prettier

Prettier enforces consistent formatting across your codebase.

Setting up Prettier:

  1. Install Prettier:
bash
npm install prettier --save-dev
  1. Create a configuration file (.prettierrc):
json
{
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"semi": true
}
  1. Add a format script to your package.json:
json
{
"scripts": {
"format": "prettier --write '**/*.js'"
}
}

Testing Your Express Application

Setting Up Jest for Express

  1. Install Jest and testing utilities:
bash
npm install jest supertest --save-dev
  1. Create a simple test for your Express routes:
javascript
// tests/routes.test.js
const request = require('supertest');
const app = require('../app');

describe('User API', () => {
test('GET /api/users should return 200 and users array', async () => {
const response = await request(app).get('/api/users');

expect(response.status).toBe(200);
expect(Array.isArray(response.body)).toBe(true);
});
});
  1. Add test script to package.json:
json
{
"scripts": {
"test": "jest"
}
}

Code Organization Best Practices

Express Project Structure

A well-organized Express application typically follows this structure:

project-root/
├── config/ # Configuration files
├── controllers/ # Request handlers
├── middleware/ # Custom middleware
├── models/ # Data models
├── routes/ # Route definitions
├── services/ # Business logic
├── utils/ # Helper functions
├── tests/ # Test files
├── app.js # Express application setup
└── server.js # Server entry point

Example Implementation

Here's an example of well-structured Express code:

javascript
// routes/user.routes.js
const express = require('express');
const userController = require('../controllers/user.controller');
const authMiddleware = require('../middleware/auth.middleware');

const router = express.Router();

router.get('/', userController.getAllUsers);
router.get('/:id', userController.getUserById);
router.post('/', authMiddleware.verifyToken, userController.createUser);
router.put('/:id', authMiddleware.verifyToken, userController.updateUser);
router.delete('/:id', authMiddleware.verifyToken, userController.deleteUser);

module.exports = router;
javascript
// controllers/user.controller.js
const UserService = require('../services/user.service');

exports.getAllUsers = async (req, res, next) => {
try {
const users = await UserService.findAll();
res.status(200).json(users);
} catch (error) {
next(error);
}
};

exports.getUserById = async (req, res, next) => {
try {
const user = await UserService.findById(req.params.id);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
res.status(200).json(user);
} catch (error) {
next(error);
}
};

// Additional controller methods...

Error Handling

Good error handling is critical for high-quality Express applications.

Centralized Error Handling

javascript
// middleware/error.middleware.js
const errorHandler = (err, req, res, next) => {
const statusCode = err.statusCode || 500;

// Log error for developers
console.error(err.stack);

// Send user-friendly response
res.status(statusCode).json({
status: 'error',
message: err.message || 'Internal Server Error',
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
});
};

module.exports = errorHandler;
javascript
// app.js
const express = require('express');
const errorHandler = require('./middleware/error.middleware');
const app = express();

// Routes and other middleware
app.use('/api/users', require('./routes/user.routes'));

// Error handling middleware (must be last!)
app.use(errorHandler);

module.exports = app;

Documentation

Using JSDoc for Code Documentation

javascript
/**
* User service for database operations related to users
* @module services/user
*/

/**
* Find user by ID
*
* @async
* @param {string} id - The user's unique identifier
* @returns {Promise<Object|null>} The user object or null if not found
* @throws {Error} If database operation fails
*/
exports.findById = async (id) => {
try {
return await UserModel.findById(id);
} catch (error) {
throw new Error(`Failed to fetch user: ${error.message}`);
}
};

Code Review Checklist

When reviewing Express code, consider these quality aspects:

  1. Security: Check for potential vulnerabilities
  2. Performance: Identify bottlenecks or inefficient operations
  3. Error Handling: Ensure proper error management
  4. Code Duplication: Look for repeated logic that could be abstracted
  5. Naming Conventions: Verify clear and consistent naming
  6. Comments and Documentation: Ensure code is well-explained

Real-world Application: Building a RESTful API

Here's a practical example demonstrating high-quality Express code practices:

javascript
// app.js
const express = require('express');
const helmet = require('helmet');
const compression = require('compression');
const morgan = require('morgan');

// Import routes
const productRoutes = require('./routes/product.routes');
const errorHandler = require('./middleware/error.middleware');

// Initialize app
const app = express();

// Security middleware
app.use(helmet());

// Parse JSON requests
app.use(express.json());

// Compress responses
app.use(compression());

// Request logging
if (process.env.NODE_ENV !== 'test') {
app.use(morgan('dev'));
}

// Routes
app.use('/api/products', productRoutes);

// 404 handler
app.use((req, res) => {
res.status(404).json({ message: 'Resource not found' });
});

// Error handler
app.use(errorHandler);

module.exports = app;

Code Quality Metrics

Consider monitoring these key metrics to evaluate your Express code quality:

  1. Test Coverage: Percentage of code covered by tests
  2. Complexity: How intricate your functions are (using tools like complexity-report)
  3. Dependencies: Number and quality of external packages
  4. Code Duplication: Amount of repeated code
  5. Issues: Bugs, vulnerabilities, and code smells

Summary

Maintaining high-quality Express code involves a combination of:

  • Using proper linting and formatting tools
  • Implementing thorough testing
  • Organizing code logically
  • Handling errors effectively
  • Documenting your code
  • Conducting regular code reviews
  • Monitoring quality metrics

By integrating these practices into your development workflow, you'll create Express applications that are more maintainable, performant, and resilient.

Additional Resources

Practice Exercises

  1. Set up ESLint and Prettier in an existing Express project
  2. Write tests for a set of Express routes using Jest and Supertest
  3. Refactor an Express application to use the folder structure outlined in this guide
  4. Implement centralized error handling in an Express application
  5. Add JSDoc documentation to your Express controllers and services


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)