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 use a controller module — Intermediate

Keep route files thin by delegating request logic to controller functions.
Learn: A controller module exports functions the router references by name. Each function receives (req, res, next), calls the service layer, and shapes the HTTP response. The router never calls Knex; the controller never defines URL paths—that division is the core of the Organizing Express pattern.

Supplementary examples

Thin controller calling a service

async function list(req, res, next) {
  try {
    const pastes = await service.listByUser(req.params.userId);
    res.json({ data: pastes });
  } catch (err) {
    next(err);
  }
}

Set status for create

async function create(req, res, next) {
  try {
    const paste = await service.create(req.body);
    res.status(201).json({ data: paste });
  } catch (err) {
    next(err);
  }
}

Course example

// pastes.controller.js — HTTP in/out; calls service for data
const service = require("./pastes.service");

async function list(req, res, next) {
  try {
    const pastes = await service.list(req.params.userId);
    res.json({ data: pastes });
  } catch (err) {
    next(err);
  }
}

async function create(req, res, next) {
  try {
    const paste = await service.create(req.params.userId, req.body);
    res.status(201).json({ data: paste });
  } catch (err) {
    next(err);
  }
}

module.exports = { list, create };

Additional references & examples

← All Controller (.controller.js) · Server Architecture / Routes