Step 6

The index.js file currently contains several routing related to CRUD operations on notes and users. However, it is perceivable that we will have other resources/entities in this application. Therefore, index.js is bound to get larger.

Express has a Router object that enables you to move routing logic into a separate file. We will use the express router to refactor our code.

Create a subfolder routes inside the server folder. Next, create two files in the routes folder, namely users.js and notes.js as follows.

users.js
const express = require("express");
const UserDao = require("../data/UserDao");

const router = express.Router();
const users = new UserDao();

router.get("/api/users", async (req, res) => {
  const { username, role } = req.query;
  if (username && role) {
    res
      .status(400)
      .json({
        message:
          "You must query the database based on either a username or user role.",
      });
  } else {
    const data = username
      ? await users.readOne(username)
      : await users.readAll(role);
    res.json({ data: data ? data : [] });
  }
});

router.get("/api/users/:id", async (req, res) => {
  const { id } = req.params;
  const data = await users.read(id);
  res.json({ data: data ? data : [] });
});

router.post("/api/users", async (req, res) => {
  try {
    const { username, password, role } = req.body;
    const data = await users.create({ username, password, role });
    res.status(201).json({ data });
  } catch (err) {
    res.status(err.status).json({ message: err.message });
  }
});

router.delete("/api/users/:id", async (req, res) => {
  try {
    const { id } = req.params;
    const data = await users.delete(id);
    res.json({ data });
  } catch (err) {
    res.status(err.status).json({ message: err.message });
  }
});

router.put("/api/users/:id", async (req, res) => {
  try {
    const { id } = req.params;
    const { password, role } = req.body;
    const data = await users.update(id, { password, role });
    res.json({ data });
  } catch (err) {
    res.status(err.status).json({ message: err.message });
  }
});

module.exports = router;

Notice I have replaced the app variable with the router variable and exported the router. The router is constructed as follows:

const router = express.Router();

The Router() returns an object with HTTP methods (.get, .post, .put, .delete, etc.) similar to the app object we have previously been using.

notes.js
const express = require("express");
const NoteDao = require("../data/NoteDao");

const router = express.Router();
const notes = new NoteDao();

router.get("/api/notes", async (req, res) => {
  const { query } = req.query;
  const data = await notes.readAll(query);
  res.json({ data: data ? data : [] });
});

router.get("/api/notes/:id", async (req, res) => {
  const { id } = req.params;
  const data = await notes.read(id);
  res.json({ data: data ? data : [] });
});

router.post("/api/notes", async (req, res) => {
  try {
    const { title, text } = req.body;
    const data = await notes.create({ title, text });
    res.status(201).json({ data });
  } catch (err) {
    res.status(err.status).json({ message: err.message });
  }
});

router.delete("/api/notes/:id", async (req, res) => {
  try {
    const { id } = req.params;
    const data = await notes.delete(id);
    res.json({ data });
  } catch (err) {
    res.status(err.status).json({ message: err.message });
  }
});

router.put("/api/notes/:id", async (req, res) => {
  try {
    const { id } = req.params;
    const { title, text } = req.body;
    const data = await notes.update(id, { title, text });
    res.json({ data });
  } catch (err) {
    res.status(err.status).json({ message: err.message });
  }
});

module.exports = router;

Finally update the index.js as shown below:

const db = require("./data/db");
const notes = require("./routes/notes.js");
const users = require("./routes/users.js");

const express = require("express");
const app = express();
const port = process.env.PORT || 5000;

db.connect(); // no need to await for it due to Mongoose buffering!

app.use(express.json());

app.get("/", (req, res) => {
  res.send("QuickNote API!");
});

// routing
app.use(notes);
app.use(users);

app.listen(port, () => {
  console.log(`Express app listening at port: http://localhost:${port}/`);
});

The routes related to "notes" and "users" are now encapsulated within the corresponding objects, and the express app is told to "use" them.

Try the API server in Postman to ensure this refactoring has not broken our app's behavior.