javascriptnode.jsexpressserverrouter

API Path using express router in nodejs


Using router express, I can not get paths like http://localhost:5000/api/get and http://localhost:5000/api/get/blah falling into where I want them to. I know router.js is working, because anything with /api/ works, but falls into the catch all in router.js.

e.g.

Console.log output from http://localhost:5000/api/get/blah

falling into the catch all api route
API request passed through: /api/get/blah
API request passed through:

I'd have expected this to have fallen into "router.get("/get/:dictionaryId", (req, res) => {", but it hasn't

Console.log output from http://localhost:5000/api/get

falling into the catch all api route
API request passed through: /api/get
API request passed through: /

I'd have expected this to have fallen into "router.get("/get", (req, res) => {", but it hasn't.

What am I missing?

server.js

var path = require("path");
var app = express();
var webpack = require("webpack");
var config = require("./webpack.config");
const compiler = webpack(config);
const apiRouter = require("./router"); // Import the API router

var port = 5000;

// Serve static files from the build directory
app.use(express.static(path.join(__dirname, "build")));

app.use("/api/*", apiRouter);

app.use("/api/*", (req, res, next) => {
  console.log(`API request passed through in server.js and currently won't be hit: ${req.originalUrl}`);
  next();
});

// This code makes sure that any request that does not matches a static file
// in the build folder, will just serve index.html. Client side routing is
// going to make sure that the correct content will be loaded.
app.use((req, res, next) => {
  if (/(.ico|.js|.css|.jpg|.png|.map)$/i.test(req.path)) {
    next();
  } else {
    res.header("Cache-Control", "private, no-cache, no-store, must-revalidate");
    res.header("Expires", "-1");
    res.header("Pragma", "no-cache");
    res.sendFile(path.join(__dirname, "build", "index.html"));
  }
});

app.use(
  require("webpack-dev-middleware")(compiler, {
    publicPath: config.output.publicPath,
  }),
);
app.listen(port, function (error) {
  if (error) {
    console.log(error);
  } else {
    console.log("Application running on port: " + port);
  }
});

router.js

const express = require("express");
const router = express.Router();

// Define multiple API endpoints
router.get("/api/get/", (req, res) => {
  console.log("fallen into the get1");
});
router.get("/api/get", (req, res) => {
  console.log("fallen into the get2");
});
router.get("/get", (req, res) => {
  console.log("fallen into the get3");
});
router.get("/get/", (req, res) => {
  console.log("fallen into the get4");
});
router.get("get", (req, res) => {
  console.log("fallen into the get5");
});
router.get("get/", (req, res) => {
  console.log("fallen into the get6");
});

// Define multiple API endpoints
router.get("/get/:dictionaryId", (req, res) => {
  console.log("fallen into the get");
});

router.get("*", (req, res) => {
  console.log("falling into the catch all api route");
  console.log(`API request passed through: ${req.originalUrl}`);
  console.log(`API request passed through: ${req.path}`);
});

module.exports = router;

Solution

  • The problem is in this part:

    app.use("/api/*", apiRouter);
    

    Change this to:

    app.use("/api", apiRouter);
    

    and it works. When you add an asterisk ('*') it becomes a wildcard route and if you want to proceed with it you need more specific route handling. You can read more about it in the express docs