-
-
Notifications
You must be signed in to change notification settings - Fork 285
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Route add order mechanism #29
Comments
Hello Alex, You have the same problem when you use the express method. app.get('/account/:id', cb);
app.get('/account/manager', cb); The request It is the responsibility of the developer to put his route in the right order :) For me isn't a bug. |
Yes is the same problem (order matters) but I was thinking if we can see routes not starting with Maybe is not a bug but an improvement. |
Ok I see. I think, it's a big works and behavior is unpredictable compared to the implementation that the developer will do. |
But right now is the order of apparition of methods in the class guaranteed to be kept by typescript when constructing method metadata array ? |
Typescript keeps the declaration order of the methods and therefore associated metadata. |
Hey guys, It seems like in my case, both routes will get called no matter which order I put them in. The second one would even throw an exception indicating the the headers can no longer be modified (see #37). Is there a way to Thanks in advance for any help! |
Hey @zoubarevm .
Promises isn't the cause. TsExpressDecorators use the nextFunction to call the next middleware. The nextFunction is binded with the promise returned by your method. Prevent isn't possible because with Express you can add a lot of middleware for one request/route. But I can also be mistaken. |
Error with |
@Romakita awesome, it seems like it worked. I also targeted the routes more specifically (by adding a regex to the parameter Thanks for your help! |
Hello everybody, @Get('/new')
public new (
@Request() req: Express.Request,
@Response() res: Express.Response,
) {
console.log('new');
return new Promise((resolve, reject) => {
resolve('new');
}).then(d => {
res.send(d);
});
}
@Get('/:id')
public param (
@PathParams('id') id: string,
@Request() req: Express.Request,
@Response() res: Express.Response,
) {
console.log('param');
res.send(id);
} It will log both Console:
|
Hi @m0uneer First case: @Get('/new')
public new (
@Request() req: Express.Request
) {
console.log('new');
return new Promise((resolve, reject) => {
resolve('new');
});
} You don't need to use response if you want just return the "new" data. ts-express-decorators will sent the response automatically. But in some case you need to send manually your response. In this case, don't return a promise. Just do that: @Get('/new')
public new (
@Request() req: Express.Request,
@Response() res: Express.Response,
) {
console.log('new');
// remove return instruction.
new Promise((resolve, reject) => {
resolve('new');
}).then(d => {
res.send(d);
});
} In your case you have problem your routes implementation. When you give theses routes:
express will resolve the two routes when the called route is I will not change the behavior of Express ! So I recommend you to change your implementation to do not have two routes that can be resolved at the same time for one request, if that's not what you want. Here an example that will work fine: @Get('/') // remove new or change the second routes
public new (
@Request() req: Express.Request,
@Response() res: Express.Response
) {
console.log('new');
// 1st usecase
response.send('new');
// or by promise
return new Promise((resolve, reject) => {
resolve('new');
});
}
@Get('/:id') // or @Get('find/:id') or other stuff that not match with the first route.
public param (
@PathParams('id') id: string,
@Request() req: Express.Request,
@Response() res: Express.Response,
) {
console.log('param');
res.send(id);
} I hope my explanation will help you. See you, |
@Romakita, Thanks a lot Romain your explanations helps a lot. I rechecked Express Doc and found that I must call public invokeMethod(settings: IInjectableMiddlewareMethod, localScope: IInvokableScope): any {
...
return new Promise((resolve, reject) => {
...
Promise
.resolve()
.then(() => {
...
})
.then((data) => {
if (data !== undefined) {
localScope.request.storeData(data);
}
if (!hasNextFn || isPromise) {
resolve();
}
})
.catch(reject);
})
.then(
() => {
next(); // <--- Here is my question
},
(err) => {
next(err);
}
);
} Isn't this |
Waiting your prompt response @Romakita :) |
Hi @m0uneer, To use promise with Express, I'm obliged to ask Express to pass me the next function. If I don't get the next function, the middleware will be finished before the Promise has finished his execution. When you get the next express function, you must to call this. If you don't that, Express wouldn't call the next middleware. Even if you send a response in your middleware, you must call the next express function. But if you use Express, you certainly know this use case to send a response: app.get("/", function (request, response) {
response.send("data");
}); This code don't call the next express function. Express, call implicitly the next function for you ! It's an equivalent to: app.get("/", function (request, response, next) {
response.send("data");
next();
}); Finally, I take your code in pure express implementation app
.get("/new", function (request, response) {
response.send("data1");
})
.get("/:id", function (request, response) {
response.send("data2");
}); You will have a conflict and you will get an error when you call /new => headers are already sent. To answer to your question, here the complete code: return new Promise((resolve, reject) => {
let parameters, isPromise: boolean;
localScope.next = reject; // ! IMPORTANT
Promise
.resolve()
.then(() => {
const result = handler()(...parameters);
isPromise = result && result.then;
return result;
})
.then((data) => {
if (data !== undefined) {
localScope.request.storeData(data);
}
if (!hasNextFn || isPromise) {
resolve(); // (1)
}
})
.catch(reject);
})
.then(
() => {
next(); // and (1)
},
(err) => {
next(err); // (2)
}
); The function call that you pointed will be called in this cases:
myMethod() {
return Promise.resolve({});
} => isPromise = true, hasNextFn = false
myMethod(@Next() next) {
next() // or next(new Error());
} => isPromise = false, hasNextFn = true
myMethod() {
return {};
} => isPromise = false, hasNextFn = false
myMethod(request, response, next) => isPromise = false, hasNextFn = true
myMethod(@Next()){
next("next data");
return Promise.resolve("promise data");
} => isPromise = true, hasNextFn = true But I know, I have one case where this script doesn't works fine:
myMethod(request, response){} => isPromise = false, hasNextFn = false See you :) |
I tried a pure javascript installation of express to make sure this behavior is normal but unfortunately, the next middleware is never called without injecting next and calling it. router.get('/test', function (req, res) {
console.log(1); // logged and server hangs
}, function (req, res, next) {
console.log(2); // never been called
res.json();
}); And I returned to documentation but couldn't find any useful info about this bahaviour. Could you please refer to the documentation of Express for this? |
Hi @m0uneer , In this case, I'm not sure if express follow the rules that I had explained. I'll tried ASAP ;) This example works: router.use(function (req, res) {
console.log(1); // logged and server hangs
})
.use(function (req, res, next) {
console.log(2); // logged and server hangs
next();
}) But It didn't work in this case: router.use(function (req, res, next) { // next is injected but never called
console.log(1); // logged and server hangs
})
.use(function (req, res, next) {
console.log(2); // never log
next();
}) Here a link on the middleware, maybe you can find the right explication: See you |
I'm sorry, Romain, but the first and second example are not working... both only log Consider the following: @Get('/posts')
public async getPost (@PathParams('postId') postId: number,
@Response() res: Express.Response) {
const hasAccess = await this.hasUserAccess(postId);
if (!hasAccess) {
res.status(401).json({
level: 'core',
redirectUrl: 'A URL'
});
return;
}
return this.postService.getPost(postId);
}
@Get('/:id')
public async anyDummyMethod (){
}
I want to use As I understand your point of view, this will not work properly. So what do you think? |
Hi @m0uneer, I'm sorry for the bad example... I'm surprised too. I have two proposal for your problem : With Middlewareimport {Unauthozised} from "ts-httpexceptions";
@Middleware()
export class AccessPostMiddleware {
use(@PathParams('postId') postId: number, @Response() response, @Next() next) {
if(!this.hasUserAccess(postId)) {
next(new Unauthozised(json.stringify({
level: 'core',
redirectUrl: 'A URL'
})));
} else {
next();
}
}
private hasUserAccess(postId) {
return true;
}
}
@Controller("/")
class SomeClass {
@Get("/:id")
@UseBefore(AccessPostMiddleware)
public async getPost (@PathParams("postId") postId: number) {
return this.postService.getPost(postId);
}
} In addition, you can create your custom decorator like this: export function AccessPost (target, propertyKey, descriptor) {
return UseBefore(AccessMiddleware)(target, propertyKey, descriptor);
} then: @Controller("/")
class SomeClass {
@Get("/:id")
@AccessPost
public async getPost (@PathParams("postId") postId: number) {
return this.postService.getPost(postId);
}
} With throwing exceptionimport {Unauthozised} from "ts-httpexceptions";
class PostCtrl {
@Get('/posts')
public async getPost (@PathParams('postId') postId: number) {
const hasAccess = await this.hasUserAccess(postId);
if (!hasAccess) {
throw new Unauthozised(json.stringify({
level: 'core',
redirectUrl: 'A URL'
}));
return;
}
return this.postService.getPost(postId);
}
@Get('/:id')
public async anyDummyMethod (){
}
} Middleware approach is more reusable (with decorator). But it's maybe overkill in your case ^^. Actually, I work on your problem to solve it in the future version. But, promisify express middleware it's very hard with all possible use case... See you, |
Thanks Romain for your proposals, but they both don't solve the problem of the conflict. Also the way you throw the |
Hi Romain, Any news about this issue? and I think it should be Thanks for your help |
Hi @m0uneer , My apologize :( Have you test the 1.4.11 ? I've added some fix about this feature. If this version didn't solve it, you can set the @ServerSettings({debug: true})
class Server extends ServerLoader {} Send me the log trace when you have your error :) (since the first trace with incoming request). See you, |
Thanks, Romain, I tried your last version but routes still conflict. This is an example (of many) to reproduce the conflict @Get('/test')
public test () {
return 'test';
}
@Get('/:id')
public get (@PathParams('id') id: number) {
return 'id';
} Log Trace: [DEBUG] [#1] -- Incoming request --------------------------------------------------------
[DEBUG] [#1] Route => GET /api/test
[DEBUG] [#1] Request.id => 1
[DEBUG] [#1] Headers => {"host":"192.168.1.101:3020","connection":"keep-alive","postman-token":"1f5979d6-aec3-0bc4-11fb-aa1c555424c4","cache-control":"no-cache","x-postman-interceptor-id":"79cdef0f-5d41-1789-6dc7-d240ff1ec67f","xsrf-token":"P4OFDp6A-a12J4GvdL-t3TCO7YcFecqBa07w","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36","content-type":"application/json","accept":"*/*","accept-encoding":"gzip, deflate, sdch, br","accept-language":"en-US,en;q=0.8,ar;q=0.6,ru;q=0.4,nl;q=0.2","cookie":"connect.sid=s%3AQtiXZlJ6-nFj6Rg5Hqw0YTOH62HnzG5J.tQj9yaWp6vRLetRjnpT7X6UtDJU2htbsEc1FXAMroWs"}
[DEBUG] [#1] ----------------------------------------------------------------------------
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":false}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"cookieParser","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"cookieParser","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"compression","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"compression","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"jsonParser","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"jsonParser","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"urlencodedParser","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"urlencodedParser","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"session","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"session","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"bound initialize","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"bound initialize","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"bound authenticate","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"bound authenticate","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[WARN ] [#1] [INVOKE][DUPLICATE] The handler have been resolved twice. See your code and find if you use @Next() and Promise at the same time.
[WARN ] [#1] [INVOKE][DUPLICATE] Trace: {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true,"returnPromise":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true,"returnPromise":true}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true,"returnPromise":true}
[DEBUG] [#1] Endpoint => {"target":"Ctrl","methodClass":"test","httpMethod":"get"}
[DEBUG] [#1] [INVOKE][START] {"type":"ENDPOINT","target":"Ctrl","methodName":"test","injectable":false,"hasNextFn":false}
[DEBUG] [#1] [INVOKE][END ] {"type":"ENDPOINT","target":"Ctrl","methodName":"test","injectable":false,"hasNextFn":false,"data":"test"}
[DEBUG] [#1] [INVOKE][START] {"type":"MIDDLEWARE","target":"SendResponseMiddleware","methodName":"use","injectable":true,"hasNextFn":false}
[WARN ] [#1] [INVOKE][DUPLICATE] The handler have been resolved twice. See your code and find if you use @Next() and Promise at the same time.
[WARN ] [#1] [INVOKE][DUPLICATE] Trace: {"type":"MIDDLEWARE","target":"anonymous","injectable":false,"hasNextFn":true,"returnPromise":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"MIDDLEWARE","target":"SendResponseMiddleware","methodName":"use","injectable":true,"hasNextFn":false}
[DEBUG] [#1] Endpoint => {"target":"Ctrl","methodClass":"get","httpMethod":"get"}
[DEBUG] [#1] [INVOKE][START] {"type":"ENDPOINT","target":"Ctrl","methodName":"get","injectable":true,"hasNextFn":false}
[WARN ] [#1] [INVOKE] {"name":"BAD_REQUEST","type":"HTTP_EXCEPTION","status":400,"message":"Bad request, parameter request.params.id. Cast error. Expression value is not a number."}
[DEBUG] [#1] [INVOKE][START] {"type":"ERROR","target":"bound $onError","injectable":false,"hasNextFn":true}
BadRequest {
name: 'BAD_REQUEST',
type: 'HTTP_EXCEPTION',
status: 400,
message: 'Bad request, parameter request.params.id. Cast error. Expression value is not a number.' }
[DEBUG] [#1] [INVOKE][START] {"type":"ERROR","target":"GlobalErrorHandlerMiddleware","methodName":"use","injectable":true,"hasNextFn":true}
[DEBUG] [#1] [INVOKE][END ] {"type":"ERROR","target":"GlobalErrorHandlerMiddleware","methodName":"use","injectable":true,"hasNextFn":true,"error":{}}
[WARN ] [#1] [INVOKE] Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
at ServerResponse.header (server/node_modules/express/lib/response.js:730:10)
at ServerResponse.res.json (server/dist/app.js:131:28)
at Server.$onError (server/dist/app.js:216:13)
at server/node_modules/ts-express-decorators/src/services/middleware.ts:283:45
at propagateAslWrapper (server/node_modules/async-listener/index.js:468:23)
at server/node_modules/async-listener/glue.js:188:31
at server/node_modules/async-listener/index.js:505:70
at server/node_modules/async-listener/glue.js:188:31
[WARN ] [#1] [INVOKE] Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
at ServerResponse.header (server/node_modules/express/lib/response.js:730:10)
at ServerResponse.res.json (server/dist/app.js:131:28)
at Server.$onError (server/dist/app.js:216:13)
at server/node_modules/ts-express-decorators/src/services/middleware.ts:283:45
at propagateAslWrapper (server/node_modules/async-listener/index.js:468:23)
at server/node_modules/async-listener/glue.js:188:31
at server/node_modules/async-listener/index.js:505:70
at server/node_modules/async-listener/glue.js:188:31
info: GET /api/test 400 959ms statusCode=400, url=/api/test, host=192.168.1.101:3020, connection=keep-alive, postman-token=1f5979d6-aec3-0bc4-11fb-aa1c555424c4, cache-control=no-cache, x-postman-interceptor-id=79cdef0f-5d41-1789-6dc7-d240ff1ec67f, xsrf-token=P4OFDp6A-a12J4GvdL-t3TCO7YcFecqBa07w, user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36, content-type=application/json, accept=*/*, accept-encoding=gzip, deflate, sdch, br, accept-language=en-US,en;q=0.8,ar;q=0.6,ru;q=0.4,nl;q=0.2, cookie=connect.sid=s%3AQtiXZlJ6-nFj6Rg5Hqw0YTOH62HnzG5J.tQj9yaWp6vRLetRjnpT7X6UtDJU2htbsEc1FXAMroWs, method=GET, httpVersion=1.1, originalUrl=/api/test, , responseTime=959
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
at ServerResponse.header (server/node_modules/express/lib/response.js:730:10)
at ServerResponse.res.json (server/dist/app.js:131:28)
at Server.$onError (server/dist/app.js:216:13)
at server/node_modules/ts-express-decorators/src/services/middleware.ts:283:45
at propagateAslWrapper (server/node_modules/async-listener/index.js:468:23)
at server/node_modules/async-listener/glue.js:188:31
at server/node_modules/async-listener/index.js:505:70
at server/node_modules/async-listener/glue.js:188:31
The Express way, a request to You're implementations consider some useful use cases but they are strange for someone familiar with Express known use cases. Also, those implementations are causing problems and there are no working proposals from your replies above. Thanks for your sincere patience and support, Romain Mouneer |
Hi @m0uneer , I'll fix that ASAP. Thanks for the log trace :) |
Thanks, Romain :) |
HI @m0uneer , It's fixed :D v1.4.12 See you |
Thanks, Romain, The conflict itself has been fixed but what if I want to navigate through two route handlers. The fix has blocked this use case. @Get('/:id')
public assert (@PathParams('id') id: number,
@Next() next: Function) {
return assert().then(() => { // Please notice that `return` here is not optional
// if i want use async/await. e,i `public async assert(...`.
next(); // I expect `next()` to call the next handler but it doesn't.
});
}
@Get('/:id')
public get (@PathParams('id') id: number) {
// This handler isn't called.
return 'id';
} What do you think? Thanks a lot Romain |
I thinks if you try the same example in express version, you'll have the same problem :) app.get(':id', (request, response, next) => {
console.log('ID1');
Promise.resolve().then(() => {
next();
});
})
app.get(':id', (request, response) => { // will be ignored by express
console.log('ID1');
response.send("id")
}) I thinks your approach isn't the good way. Two handler on the same route add twice with app.get() (or other method) will give a problem. If you need to have to handler on same route, you need to use the first handler as middleware and the second as an Endpoint. So you can solve your problem like this: public assert (@PathParams('id') id: number,
@Next() next: Function) {
return Promise.resolve().then(() => {
next(); // not necessary normally but why not, I accept this challenge :p
});
}
@Get('/:id', this.assert)
public get (@PathParams('id') id: number) {
// This handler isn't called.
return 'id';
}
But with the experience, I'll preferred to use Middleware abstraction with the decorators. Maybe you case try this: @Middleware()
export class CustomMiddleware {
use(@PathParams('id') id: number,
@Next() next: Function) {
return Promise.resolve().then(() => {
next(); // not necessary normally but why not, I accept this challenge :p
});
}
}
@Controller("/")
class SomeClass {
@Get("/:id")
@UseBefore(CustomMiddleware)
public get (@PathParams('id') id: number) {
// This handler isn't called.
return 'id';
}
}
You have the choice :) |
I will try it myself today and let you know ... thanks again Romain |
Unfortunately, I tried it and I found it valid express implementation. (I'm also sure :D, I've just tested it) Also, I see that my approach is good because:
So I see it's a bug :) Thanks, Romain |
Well, if your example with Express work can you forward me the code. Maybe I forgot something. |
Sorry. I'll just re tested this case with another project and you've right... never answer to a question when I'm tired XD. I'll inspect the problem and fix that. If isn't a big problem... |
Fixed with v1.4.15 |
Great Romain ... It now works! ... Thanks for your support :) |
@m0uneer And thanks for your patience ^^. |
@Romakita seems this bug raised up in v5.9.0 again |
Hi @ArtemDerevnjuk, I’ll check that tomorrow, but It should works. It’s covered by one of my e2e test :) |
Hello @ArtemDerevnjuk Can you check different examples and tell me if one of this match with your usecase/issue or not. Probably I missed something, but today all usecases described in ResponseScenarioCtrl are officially supported. See you, |
@Romakita Hi) Thanks for quick reply! |
Problem with the different endpoints which have the same or near route pattern. In progress |
Hi @Romakita ! e.g if i have something like below
i'd have to switch and declare
to prevent request went to |
@vembry yes you have to switch methode order (like with a pure express app). order is determined by code implementation which is totally logic ^^. See you |
i apologize, apparently it's already covered in the documentation here |
No worries ;) |
The order of adding routers to express matters. For example if we have following class.
Request
GET /account/manager
Expected
Method
getManagerAccount()
respondActual
Method
getAccountById()
will respond withmanager
injected asid
Workaround
Conclusion
When adding Routers to express app, fixed routes should go first then parametrised ones.
The text was updated successfully, but these errors were encountered: