Well-structured backends separate concerns: routers define URLs, controllers translate HTTP to application calls, services own data access, and middleware handles cross-cutting behavior (validation, 404, errors). Study these patterns to keep files small, testable, and aligned with REST conventions.

How to define routes on the app directly — Basic

Attach handlers with app.get/post before splitting logic into router modules.
Learn: Defining routes directly on `app` is fine for tiny projects or quick experiments. As endpoints multiply, inline handlers become hard to test and navigate—splitting into router modules keeps each file responsible for one resource area.

Supplementary examples

GET and POST on the app

app.get("/pastes", (req, res, next) => list(req, res, next));
app.post("/pastes", (req, res, next) => create(req, res, next));

Route parameters on the app

app.get("/users/:userId", (req, res) => {
  const { userId } = req.params;
  res.json({ userId });
});

Course example

// New middleware function to validate the request body
function bodyHasTextProperty(req, res, next) {
const { data: { text } = {} } = req.body;
if (text) {
return next(); // Call `next()` without an error message if the result exists
}
next("A 'text' property is required.");
}
let lastPasteId = pastes.reduce((maxId, paste) => Math.max(maxId, paste.id), 0);
app.post(
"/pastes",
bodyHasTextProperty, // Add validation middleware function
(req, res) => {
// Route handler no longer has validation code.
const { data: { name, syntax, exposure, expiration, text, user_id } = {} } = req.body;
const newPaste = {
id: ++lastPasteId, // Increment last id then assign as the current ID
name,
syntax,
exposure,
expiration,
text,
user_id,
};
pastes.push(newPaste);
res.status(201).json({ data: newPaste });
}
);

Additional references & examples

← All Building routes · Server Architecture / Routes