Home > OS >  ExpressJS: Best way to separate routes and accepting params?
ExpressJS: Best way to separate routes and accepting params?

Time:01-08

I made a Express.js system where the files in the /routes folder are acting as a classic route (but with one file per route)

Example: /routes/get/user.js will be accessible with http://localhost:8080/user (the /get is to separate methods, it can be /post, /put...)

Here's my entire index.js file: https://pastebin.com/ALtSeHXc

But actually, my problem is that I can't pass params into the url like https://localhost:8080/user/random_id_here.

With this system, I think the best idea is to find a way to pass params on separated files too, but I don't know how can it be done...

Here's an example of one of my separated file:

module.exports = class NameAPI {
    constructor(client) {
        this.client = client
    }

    async run(req, res) {
        // Code here
    }
}

Maybe you'll have a better system, or a solution for this. Thanks.

CodePudding user response:

I generally would setup my express to handle this way in that case you want a dynamic insert. This is personal code so do make the adjustments necessary or observe the behavior! :)

WEBAPP.get('/room/:name', (req, res) => {
  // Check if URL ends with / (in my case I don't want that)
    if (req.url.endsWith('/')) return res.redirect('/');
  // Check if URL param "name" matches my regex ex. Username1920 or redirect them
    if (req.params.name.match(/^[a-zA-Z0-9]{3,24}$/) === null) return res.redirect('/');
  // render the room (sending EJS)
    res.render('room', {
        title: req.params.name.toUpperCase()
    });
});
/*

/*This example accepts one param and must follow my regex/rules*/

So if you were handed /room/test12345 your req.params.name would return a value. Notice the colon to define a param, so you could have /:room/:user/:request and it'd return: req.params.room, req.params.user, req.params.request all defined! :)

CodePudding user response:

You can get the optional params from the module object you already have so each module specifies its own params. This example below shows just adding new params on after the module name, but you could extend this feature to be richer if you needed to.

In a simple implementation, in your loader, you can change this:

   posts.forEach((post) => {
        const module = new (require(`./routes/post/${post}`))(this);
        this.api.post(`/${post}`, async (req, res) => await module.run(req, res))
    })

to this:

   posts.forEach((post) => {
        const module = new (require(`./routes/post/${post}`))(this);
        const urlParams = module.params || "";
        this.api.post(`/${post}${urlParams}`, async (req, res) => module.run(req, res))
    });

So, if a given route wanted the extra URL param /:id added to it, then it would just define the .urlParams property on its exported module object to be `"/:id" and that would be automatically included in the route definition.


P.S. Most of the code in each of the branches of your switch statement in _loadHttpMethode() is identical. With a little factoring into a common function and one or two parameters passed to that function, you can eliminate all the copied code among those different branches of the switch so all each switch does is call one function and pass it a few arguments.

Another note. The code you currently show will not run because you're using an await in here: this.api.post(/${post}, async (req, res) => await module.run(req, res)), but this is not in an async function. It's in the callback to posts.forEach() which is not declared as async. First off, there's probably no need for that await. If there is, then just change the .forEach() to a for/of and it will be then operating in the parent function scope instead of a callback scope which is already async.

  •  Tags:  
  • Related