Post

Epoch 2: Build the User Service (ExpressJS)

This epoch focuses on building the user-service using Node.js, ExpressJS, and MongoDB. The service will include user registration and login functionality, secured using JWT (JSON Web Token). Students will learn how to structure an Express project as a standalone microservice with its own database, controller, and routing layers.

Epoch 2: Build the User Service (ExpressJS)

Objectives

  • Create a REST API using ExpressJS and connect it to MongoDB.
  • Design and validate a user schema using Mongoose.
  • Implement user registration and login endpoints.
  • Generate and verify JWTs for authentication.
  • Structure a microservice project using best practices.

1. Microservice Overview

  • Service Name: user-service
  • Responsibility: Manage all user-related operations such as registration, login, and authentication.
  • Technology Stack: Node.js, ExpressJS, MongoDB (via Mongoose), JWT

2. Structure architechture

1
2
3
4
5
6
7
8
9
10
11
12
13
14
user-service/
├── controllers/
│   └── auth.controller.js
├── models/
│   └── user.model.js
├── routes/
│   └── auth.routes.js
├── middlewares/
│   └── validateToken.js
├── utils/
│   └── jwt.js
├── .env
├── server.js
├── package.json

2.1. ExpressJS Setup

Install necessary packages:

1
2
npm init -y
npm install express mongoose dotenv jsonwebtoken bcryptjs

Basic Express server setup (server.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const express = require('express');
const mongoose = require('mongoose');
require('dotenv').config();

const app = express();
app.use(express.json());

// Routes
app.use('/api/auth', require('./routes/auth.routes'));

mongoose.connect(process.env.MONGO_URI)
  .then(() => app.listen(process.env.PORT, () => {
    console.log(`User service running on port ${process.env.PORT}`);
  }))
  .catch(err => console.error(err));

2.2. User Schema (Mongoose)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// models/user.model.js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
  name: String,
  email: { type: String, unique: true },
  password: String,
  role: { type: String, default: 'customer' }
});

userSchema.pre('save', async function(next) {
  if (this.isModified('password')) {
    this.password = await bcrypt.hash(this.password, 10);
  }
  next();
});

module.exports = mongoose.model('User', userSchema);

2.3 Authentication Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// controllers/auth.controller.js
const User = require('../models/user.model');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');

exports.register = async (req, res) => {
  const { name, email, password } = req.body;
  try {
    const user = new User({ name, email, password });
    await user.save();
    res.status(201).json({ message: 'User registered successfully.' });
  } catch (err) {
    res.status(400).json({ error: 'Registration failed.' });
  }
};

exports.login = async (req, res) => {
  const { email, password } = req.body;
  try {
    const user = await User.findOne({ email });
    if (!user || !await bcrypt.compare(password, user.password))
      return res.status(401).json({ error: 'Invalid credentials' });

    const token = jwt.sign({ userId: user._id, role: user.role }, process.env.JWT_SECRET);
    res.json({ token });
  } catch (err) {
    res.status(500).json({ error: 'Login failed.' });
  }
};

2.4. Routes

1
2
3
4
5
6
7
8
// routes/auth.routes.js
const router = require('express').Router();
const { register, login } = require('../controllers/auth.controller');

router.post('/register', register);
router.post('/login', login);

module.exports = router;

2.5. Environment Variables (.env)

PORT=4001
MONGO_URI=mongodb://localhost:27017/user-service
JWT_SECRET=your_jwt_secret

4. API Testing with Postman

MethodEndpointPayloadDescription
POST/api/auth/register{ name, email, password }Register new user
POST/api/auth/login{ email, password }Log in and receive token
  • Set Content-Type: application/json in headers.
  • On successful login, copy the JWT token to use for protected routes in later epochs.
This post is licensed under CC BY 4.0 by the author.