DEV Community

Cover image for Understanding Express Routes, Controllers, and Services: A Beginner's Guide - Node.js Tutorial - Part 12
Abdelhakim mohamed
Abdelhakim mohamed

Posted on

Understanding Express Routes, Controllers, and Services: A Beginner's Guide - Node.js Tutorial - Part 12

Introduction

If you're new to Express.js or Node.js, you might have heard about "routes," "controllers," and "services." At first, these terms sound technical, but trust me—understanding them can really transform how you build your apps. Not only will your code look cleaner, but it'll also make your life easier as your app grows. In this guide, we'll break down what each of these components does and why separating them is a game-changer for any Express project.

Let's start by setting up a basic Express app and organizing everything like a pro!


Setting Up Your Project

First things first—let’s create a new Node.js project. Fire up your terminal and follow these steps:

  1. Initialize your project by running:
   npm init -y
Enter fullscreen mode Exit fullscreen mode
  1. Install Express to get the magic going:
   npm install express
Enter fullscreen mode Exit fullscreen mode
  1. Now, let’s structure our project to keep things clean. Here’s how your folder setup should look:
my-express-app
│
├── src
│   ├── controllers
│   ├── routes
│   ├── services
│
├── app.js
└── package.json
Enter fullscreen mode Exit fullscreen mode

Image description

We'll walk through what goes into each of these folders. Don't worry if this looks like a lot; it's easier than it seems!.


Routes: The Traffic Cops of Your App

Think of routes as traffic cops—they decide where each request should go. They don’t do much heavy lifting themselves but delegate the real work to controllers.

Here’s how you can create a basic route for user-related requests:

// src/routes/userRoutes.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');

// Define routes
router.get('/users', userController.getAllUsers);
router.post('/users', userController.createUser);

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

In this example, when someone hits /users with a GET request, our app calls the getAllUsers function from the controller. Pretty neat, right?


Controllers: The Brains of the Operation

Now, controllers are where the logic happens. They take what the routes send their way and handle all the complex stuff like fetching data or saving a new user.

Let’s build a simple controller:

// src/controllers/userController.js
const userService = require('../services/userService');

exports.getAllUsers = (req, res) => {
  const users = userService.fetchUsers();
  res.status(200).json(users);
};

exports.createUser = (req, res) => {
  const newUser = userService.addUser(req.body);
  res.status(201).json(newUser);
};
Enter fullscreen mode Exit fullscreen mode

Here, the controller is getting data from a service (which we'll talk about next) and sending a response back. Think of the controller as the middleman between routes and services—it doesn't handle data directly but knows who to ask.


Services: The Real Workers

Services handle the real business logic, like interacting with a database or managing data. This keeps your controllers nice and clean.

Check out this basic service that manages a list of users:

// src/services/userService.js
const users = [];

exports.fetchUsers = () => {
  return users;
};

exports.addUser = (user) => {
  users.push(user);
  return user;
};
Enter fullscreen mode Exit fullscreen mode

Here, we’re storing users in an array (for simplicity). Services help keep your controllers lightweight and focused on handling requests instead of worrying about the data itself.


Bringing It All Together in app.js

Once you have your routes, controllers, and services set up, you need to wire everything together in your main application file (app.js):

// app.js
const express = require('express');
const app = express();
const userRoutes = require('./src/routes/userRoutes');

app.use(express.json());
app.use('/api', userRoutes);

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

In this file, we tell Express to use our userRoutes for any requests that start with /api. This makes it easy to organize all your routes under one common base path.


How Your Final Directory Should Look

Once you've set up everything, your directory structure should look something like this:

my-express-app
│
├── src
│   ├── controllers
│   │   └── userController.js
│   ├── routes
│   │   └── userRoutes.js
│   ├── services
│   │   └── userService.js
│
├── app.js
└── package.json
Enter fullscreen mode Exit fullscreen mode

Wrapping Up

By splitting your app into routes, controllers, and services, you've just taken the first step towards writing better, cleaner code! Not only does this make your project easier to manage now, but it also saves you headaches as your app gets more complex. Plus, your future self (and your teammates) will thank you!

Happy Coding😊

Top comments (0)