Guide to Structuring Express.js Applications

Welcome to our comprehensive guide on building structured web applications using Express.js!

Whether you’re a beginner or an experienced developer, this post will walk you through creating a well-organized Express.js application with best practices in mind.

By the end of this guide, you’ll have a solid understanding of how to structure your code. You will also know how to implement routing and handle errors. There is more to learn as well.

Let’s dive in!

Table of Contents

  • Introduction to Express.js
  • Setting Up Your Project
  • Structuring Your Application
  • Implementing Routes and Controllers
  • Handling Errors Gracefully
  • Using Environment Variables
  • Conclusion

1. Introduction to Express.js

Express.js is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.

Advertisements

It’s known for its simplicity and ease of use, making it a popular choice among developers.

2. Setting Up Your Project

To get started, you’ll need to set up your project. First, create a new directory for your application and navigate into it:

Fish
mkdir my-express-app
cd my-express-app

Next, initialize a new Node.js project and install the necessary dependencies:

Fish
npm init -y
npm install express body-parser dotenv

Create a .env file to store your environment variables:

Fish
PORT=3000

Now, let’s create the main application file, app.js:

JavaScript
const express = require('express');
const bodyParser = require('body-parser');
const indexRouter = require('./routes/index');
const usersRouter = require('./routes/users');
const errorHandler = require('./middleware/errorHandler');
require('dotenv').config();

const app = express();

// Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

// Routes
app.use('/', indexRouter);
app.use('/users', usersRouter);

// Error handling middleware
app.use(errorHandler);

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

3. Structuring Your Application

A well-structured application is easier to maintain and scale. Here’s a suggested project structure:

my-express-app/
├── app.js
├── routes/
│ ├── index.js
│ └── users.js
├── middleware/
│ └── errorHandler.js
├── controllers/
│ └── userController.js
├── models/
│ └── userModel.js
├── package.json
└── .env

4. Implementing Routes and Controllers

Routes define the endpoints of your application, while controllers handle the logic for each route. Let’s create some routes and controllers.

routes/index.js

JavaScript
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
  res.send('Welcome to the Express.js app!');
});

module.exports = router;
Expand

routes/users.js

JavaScript
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');

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

module.exports = router;
Expand

controllers/userController.js

JavaScript
const userModel = require('../models/userModel');

exports.getAllUsers = (req, res) => {
  const users = userModel.getAllUsers();
  res.json(users);
};

exports.createUser = (req, res) => {
  const newUser = userModel.createUser(req.body);
  res.status(201).json(newUser);
};

exports.getUserById = (req, res) => {
  const user = userModel.getUserById(req.params.id);
  if (user) {
    res.json(user);
  } else {
    res.status(404).send({ error: 'User not found' });
  }
};

exports.updateUser = (req, res) => {
  const updatedUser = userModel.updateUser(req.params.id, req.body);
  if (updatedUser) {
    res.json(updatedUser);
  } else {
    res.status(404).send({ error: 'User not found' });
  }
};

exports.deleteUser = (req, res) => {
  const deletedUser = userModel.deleteUser(req.params.id);
  if (deletedUser) {
    res.json(deletedUser);
  } else {
    res.status(404).send({ error: 'User not found' });
  }
};

5. Handling Errors Gracefully

Error handling is crucial for a robust application.

Let’s create a middleware for error handling.

Read more about errors handling in Express.js: How to Handle 404 Errors in Express.js

middleware/errorHandler.js

JavaScript
const userModel = require('../models/userModel');

exports.getAllUsers = (req, res) => {
  const users = userModel.getAllUsers();
  res.json(users);
};

exports.createUser = (req, res) => {
  const newUser = userModel.createUser(req.body);
  res.status(201).json(newUser);
};

exports.getUserById = (req, res) => {
  const user = userModel.getUserById(req.params.id);
  if (user) {
    res.json(user);
  } else {
    res.status(404).send({ error: 'User not found' });
  }
};

exports.updateUser = (req, res) => {
  const updatedUser = userModel.updateUser(req.params.id, req.body);
  if (updatedUser) {
    res.json(updatedUser);
  } else {
    res.status(404).send({ error: 'User not found' });
  }
};

exports.deleteUser = (req, res) => {
  const deletedUser = userModel.deleteUser(req.params.id);
  if (deletedUser) {
    res.json(deletedUser);
  } else {
    res.status(404).send({ error: 'User not found' });
  }
};

6. Using Environment Variables

Environment variables help keep your configuration flexible and secure.

We’ve already set up a .env file to store the port number.

.env

Fish
PORT=3000

Conclusion

Congratulations! You’ve now built a well-structured Express.js application with best practices in mind.

This setup will help you maintain and scale your application as it grows. Happy coding!

What’s the next? Off course, here is How to Set Up JWT Authentication in Express.js

Leave a Comment

Scroll to Top