moleculerjs / moleculer-web

:earth_africa: Official API Gateway service for Moleculer framework
http://moleculer.services/docs/moleculer-web.html
MIT License
291 stars 119 forks source link

Multiple routes with same path #262

Closed nzy closed 2 years ago

nzy commented 3 years ago

In previous versions I did this and it worked fine:

{
    path: '/api',
    authorization: true,
    mappingPolicy: "restrict",
    aliases: {
        GET /users": "users.list",
        GET /user": "users.me",
        GET /users/:id": "users.get",
        PUT /users/:id": "users.update"
    }
    //Parse body content
    bodyParsers: {
        json: { strict: false },
        urlencoded: { extended: true }
    },
},
{
    path: '/api',
    mappingPolicy: "restrict",
    aliases: {
        "GET /test"(req, res) {
            res.end('This is test')
        }
    },
    bodyParsers: {
        json: { strict: false },
        urlencoded: { extended: true }
    }
},
{
    path: "/api",
    authorization: true,
    mappingPolicy: "restrict",
    bodyParsers: {
        json: false,
        urlencoded: false
    },
    aliases: {
        // File upload from HTML multipart form
        "POST /avatar": "multipart:file.save"
    },
    busboyConfig: {
        limits: { files: 1 }
    },
}

But in v. 0.10.0 this code doesn't work. I have to make various path values to make it work.

srosset81 commented 3 years ago

Indeed, the mecanism to detect same routes is too simple: https://github.com/moleculerjs/moleculer-web/blob/master/src/index.js#L1121

icebob commented 3 years ago

@nzy please create a simple repro code.

nzy commented 2 years ago

I want to make routes with the base path = '/api', but with different options.

Like "GET /api/users/:id" with option authorization = true, and "GET /api/image" with no authorization, and "POST /api/avatar" with authorization and no body parser.

Now I have to code routes like this, for example:

routes: [
    {
        path: '/api',
        authorization: true,
        mappingPolicy: "restrict",
        aliases: {
            "GET /logs": "logs.list",
            "GET /users": "users.list",
            "GET /user": "users.me",
            "GET /users/:id": "users.get",
            "PUT /users/:id": "users.update",
        },
        bodyParsers: {
            json: { strict: false },
            urlencoded: { extended: true }
        },
    },
    {
        path: '',
        mappingPolicy: "restrict",
        aliases: {
            "POST /api/users/login": "users.login",
            "GET /api/image": "file.get",
            "POST /api/send/feedback": "mail.sendFeedback",
            "GET /api/test"(req, res) {
                res.end('This is test')
            }
        },
        bodyParsers: {
            json: { strict: false },
            urlencoded: { extended: true }
        }
    },
    {
        path: "/api/users",
        authorization: true,
        mappingPolicy: "restrict",
        bodyParsers: {
            json: false,
            urlencoded: false
        },
        aliases: {
            // File upload from HTML multipart form
            "POST /avatar": "multipart:file.save",
        },
        busboyConfig: {
            limits: { files: 1 }
        },
    }
]

But this is not good.

I want to do routes something like that:

routes: [
    {
        path: '/api',
        authorization: true,
        mappingPolicy: "restrict",
        aliases: {
            "GET /logs": "logs.list",
            "GET /users": "users.list",
            "GET /user": "users.me",
            "GET /users/:id": "users.get",
            "PUT /users/:id": "users.update",
        },
        bodyParsers: {
            json: { strict: false },
            urlencoded: { extended: true }
        },
    },
    {
        path: '/api',
        mappingPolicy: "restrict",
        aliases: {
            "POST /users/login": "users.login",
            "GET /image": "file.get",
            "POST /send/feedback": "mail.sendFeedback",
            "GET /test"(req, res) {
                res.end('This is test')
            }
        },
        bodyParsers: {
            json: { strict: false },
            urlencoded: { extended: true }
        }
    },
    {
        path: "/api",
        authorization: true,
        mappingPolicy: "restrict",
        bodyParsers: {
            json: false,
            urlencoded: false
        },
        aliases: {
            // File upload from HTML multipart form
            "POST /users/avatar": "multipart:file.save",
        },
        busboyConfig: {
            limits: { files: 1 }
        },
    }
]

Or even:

path: '/api',
routes: [
    {
        authorization: true,
        mappingPolicy: "restrict",
        aliases: {
            "GET /logs": "logs.list",
            "GET /users": "users.list",
            "GET /user": "users.me",
            "GET /users/:id": "users.get",
            "PUT /users/:id": "users.update",
        },
        bodyParsers: {
            json: { strict: false },
            urlencoded: { extended: true }
        },
    },
    {
        mappingPolicy: "restrict",
        aliases: {
            "POST /users/login": "users.login",
            "GET /image": "file.get",
            "POST /send/feedback": "mail.sendFeedback",
            "GET /test"(req, res) {
                res.end('This is test')
            }
        },
        bodyParsers: {
            json: { strict: false },
            urlencoded: { extended: true }
        }
    },
    {
        authorization: true,
        mappingPolicy: "restrict",
        bodyParsers: {
            json: false,
            urlencoded: false
        },
        aliases: {
            // File upload from HTML multipart form
            "POST /users/avatar": "multipart:file.save",
        },
        busboyConfig: {
            limits: { files: 1 }
        },
    }
]

The last last variants worked in previous versions.

icebob commented 2 years ago

I will solve it with a new name route option. If it's defined, the service will use the route.name to compare the routes. If not defined, it will use the route.path as it does right now.

        routes: [
            {
                name: "my-first-route",
                path: "/",
                aliases: {
                    hi: "greeter.hello",
                }
            },
            {
                name: "my-second-route",
                path: "/",
                aliases: {
                    "hello": "greeter.hello",
                },
                authorization: true
            }
        ]
icebob commented 2 years ago

Fixed in #273