Express App - Creating a Nested Route with ES Modules

187 views Asked by At

I've followed a tutorial to create an Express app with an API. With the tutorial completed, I am now trying to convert it from CommonJS to ES Modules. I tried looking through resources like the Express documentation but they are mostly still written in CJS, which is understandable but not very helpful for me. After a lot of troubleshooting in my app.js file and learning a bit about how to use Webpack, I've gotten pretty far in the conversion process but the one error I can't figure out relates to nested routes.

App Design Context:

Two of the app's API collections are for tour data and tour review data. One page of the app displays a tour's details including user reviews. My API has reviews that use parent referencing to tours, so I have a review route nested inside my tour router: router.use("/:tourId/reviews, reviewRouter).

Then in my review router, I have mergeParams: true so that when a request follows the route /:tourId/reviews and travels from the tour router to the review router, the review router code still has access to the request's tourID in order to retrieve parent-referenced data.

Environment:

Windows 11 OS
VS Code v1.83.1
Node v18.18.0

Error Message:

When I try to execute npm run start I get the following error in my IDE terminal: . OLD ERROR:

C:\[filePath]\[appName]\node_modules\express\lib\router\index.js:469
      throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
            ^

TypeError: Router.use() requires a middleware function but got a Module
    at Function.use (C:\[filePath]\[appName]\node_modules\express\lib\router\index.js:469:13)
    at file:///C:/[filePath]/[appName]/routes/tourRoutes.js:45:8
    at ModuleJob.run (node:internal/modules/esm/module_job:194:25)

NEW ERROR in tourRoutes.js:

file:///C:/[filePath]/[appName]/routes/tourRoutes.js:45
router.use("/:tourId/reviews", reviewRouter);
                               ^

ReferenceError: reviewRouter is not defined
    at file:///C:/[filePath]/[appName]/routes/tourRoutes.js:45:32

Relevant code - tourRoutes.js

import express from "express";

import * as tourController from "../controllers/tourController.js";
import * as authController from "../controllers/authController.js";
import reviewRoutes from "./reviewRoutes.js";

const router = express.Router();

// =======================
// TOUR ROUTES

router
  .route("/:id")
  .get(tourController.getTour)
  .patch( // middleware )
  .delete( //middleware );

// =======================
// NESTED ROUTES

// LINE 45:
router.use("/:tourId/reviews", reviewRouter);

export default router;

Relevant code - reviewRoutes.js

import express from "express";

import * as reviewController from "../controllers/reviewController.js";
import * as authController from "../controllers/authController.js";

// Allows for nested route in tourRoutes.js:
const router = express.Router({ mergeParams: true });

router
  .route("/")
  .get(reviewController.getAllReviews)
  .post(
    authController.restrictTo("user"),
    reviewController.setTourUserId,
    reviewController.createReview
  );

// Other routers with CRUD routes

export default router;

Attempted Solutions

I understand that the error is because I switched from CJS to ESM and my package.json file sets everything to modules, but when my code was using const reviewRouter = require("./reviewRoutes") CJS syntax, tourRoute.js' router.use("/:tourId/reviews, reviewRouter) code worked fine and reviewRouter was not a middleware function in and of itself - as far as I understand middleware.

If the solution is that I have to make my review router's router.route("/")... code a named function in order to export it, then I'm not sure how to do that correctly. I tried making the entire review router file code exportable with export default reviewRouter and then importing into the tour router as import { reviewRouter} from "./reviewroutes.js" but that did not work.

I also tried doing export const nestedRoute = router.route("/") couple with export default router; at the bottom of the review router, and then inside the tour router import {nestedRoute} from "./reviewroutes.js without success.

1

There are 1 answers

8
Kamran On

If you havent exported the reviewRoutes.js, please default export it as default

export default router

and on importing side dont import * as because that will import the whole module, where as we only want a middleware function so

import reviewRoutes from "./reviewRoutes.js";