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.
If you havent exported the reviewRoutes.js, please default export it as default
and on importing side dont import * as because that will import the whole module, where as we only want a middleware function so