Home > OS >  How to load API Endpoints from different folders in Express Server?
How to load API Endpoints from different folders in Express Server?

Time:10-24

I currently use my load my API endpoints using this script:

readdirSync('./routes/api').map((r) =>
  app.use(
    `/api/v1/${r.split('.')[0]}`,
    require(`./routes/api/${r.split('.')[0]}`)
  )
);

It pretty much reads everything inside the routes/api folder and the way in which I access the endpoins in POSTMAN is as follow:

{{URL}}/api/v1/posts/123
{{URL}}/api/v1/videos/123
{{URL}}/api/v1/users/123
and so on

Now what I would like to do is to create endpoints that will be used as tools, let's say, a video converter endpoint?

Furthermore I would like to put this endpoint inside an extras folder within the routes folder, exactly like the image below:

enter image description here

The way to call the endpoins inside the extras folder would then look like this:

{{URL}}/api/v1/extras/posts/123
{{URL}}/api/v1/extras/videos/123
{{URL}}/api/v1/extras/users/123
and so on

Then I decided to run my server with a second new script to see if it could run...

readdirSync('./routes/api/extras').map((r) =>
  app.use(
    `/api/v1/extras/${r.split('.')[0]}`,
    require(`./routes/api/extras/${r.split('.')[0]}`)
  )
);

Well, it did not. I got an error thrown at me:

[0] Error: Cannot find module './routes/api/extras'
[0] Require stack:
[0] - C:\xampp\htdocs\befree\server.js
[0]     at Function.Module._resolveFilename (internal/modules/cjs/loader.js:902:15)
[0]     at Function.Module._load (internal/modules/cjs/loader.js:746:27)
[0]     at Module.require (internal/modules/cjs/loader.js:974:19)
[0]     at require (internal/modules/cjs/helpers.js:93:18)
[0]     at C:\xampp\htdocs\befree\server.js:165:5
[0]     at Array.map (<anonymous>)
[0]     at Object.<anonymous> (C:\xampp\htdocs\befree\server.js:162:29)
[0]     at Module._compile (internal/modules/cjs/loader.js:1085:14)
[0]     at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
[0]     at Module.load (internal/modules/cjs/loader.js:950:32) {
[0]   code: 'MODULE_NOT_FOUND',
[0]   requireStack: [ 'C:\\xampp\\htdocs\\befree\\server.js' ]
[0] }
[0] Error Cannot find module './routes/api/extras'
[0] Require stack:
[0] - C:\xampp\htdocs\befree\server.js
[0] [nodemon] app crashed - waiting for file changes before starting...

Does any one knows if theres a way to solve this?

CodePudding user response:

fs.readdir will read all the files in the provided directory, i.e. files and directories also. This means that when executing readdirSync('./routes/api') the directory name extras will also be passed to require inside your .map callback and since it's a directory the following will be done (from the docs):

[...]if the filename passed to require is actually a directory, it will first look for package.json in the directory and load the file referenced in the main property. Otherwise, it will look for an index.js.

In your case neither of above seems to be found, hence you get the error Cannot find module './routes/api/extras'

One possible solution is to filter out directories and only process files, e.g.:

readdirSync('./routes/api')
.filter(r => fs.lstatSync('./routes/api/'  r).isFile())
.map((r) =>
  app.use(
    `/api/v1/${r.split('.')[0]}`,
    require(`./routes/api/${r.split('.')[0]}`)
  )
);

CodePudding user response:

I was not able to create routes as I wanted

/api/v1/extras/youtube
and so on

However, I was able to remove the error shown before by creating a function that iterates throught every single folder.

// Define routes
const dir = './routes/api';

function getFiles(dir) {
  return fs.readdirSync(dir).flatMap((item) => {
    // const file = item.split('.')[0];
    const routePath = `${dir}/${item}`;
    if (fs.statSync(routePath).isDirectory()) {
      return getFiles(routePath);
    }
    // return { singlefile: file, directories: routePath };
    return { item, routePath };
  });
}

const routes = getFiles(dir);

routes.map((result) => {
  app.use(
    `/api/v1/${result.item.split('.')[0]}`,
    require(`.${result.routePath.split('.')[1]}`)
  );
});

My youtube route is located in routes>api>extras>youtube.js but I still need to call it this way:

/api/v1/youtube

Which I would like to say is good enough!.

  • Related