routing-controllers icon indicating copy to clipboard operation
routing-controllers copied to clipboard

Order of routes matters

Open Christian24 opened this issue 7 years ago • 7 comments

Hello,

awesome project. I have an issue though. My JSON-Controller looks like this:

import {Router, Request, Response, NextFunction} from 'express';
import {getEntityManager, Repository} from "typeorm";
import {User} from "../models/user";
import {authService} from "../services/authservice";

import {getConnectionManager} from "typeorm";
import {JsonController} from "routing-controllers/decorator/JsonController";
import {Authorized, Body, Get, Post, Res} from "routing-controllers";


interface authData {
    password: string;
    username: string;
    email?: string;
}
@JsonController("/users")
export class UsersController {
    private userRepository: Repository<User>;

    constructor() {
        this.userRepository = getConnectionManager().get().getRepository(User);
    }


    @Post("/sign_up")
   public async   signUp(@Body() authData: authData, @Res() res: Response) {
        if (authData.username && authData.email && authData.password) {
            let user = await  this.userRepository.findOneById(authData.username);
            const count = await this.userRepository.count();
            if (!user) {
                user = new User();
                user.username = authData.username;
                user.email = authData.email;
                user = await authService.setHashedPassword(user, authData.password);
                user.admnin = count === 0;


                this.userRepository.persist(user);
                res.send(user);
            }
            else {
                res.send("Already exists");
            }
        } else {
            res.send("Incomplete");
        }
    }


    @Post("/sign_in")
   public async signIn(@Body() authData: authData, @Res() res: Response) {
        if (authData.username && authData.password) {
            let user = await  this.userRepository.findOneById(authData.username);

            if (user) {
                console.log(user);
                const valid = await authService.checkPassword(authData.password, user);
                if (valid) {
                   authService.setTokenForUser(res, user).then(() => {
                        res.send("logged in");
                    });

                } else {
                    res.send("Wrong information");
                }
            } else {
                res.send("Not found");
            }
        } else {
            res.send("Incomplete");
        }
    }
    @Authorized()
    @Get("/auto")
    public async checkAuthentication(@Res() res: Response) {
        res.send("Authorized");
    }

}

This crashes on the sign_in route. Cannot POST /users/sign_in. Funny enough if I change the order to have the GET route at the top of the class like this:

import {Router, Request, Response, NextFunction} from 'express';
import {getEntityManager, Repository} from "typeorm";
import {User} from "../models/user";
import {authService} from "../services/authservice";

import {getConnectionManager} from "typeorm";
import {JsonController} from "routing-controllers/decorator/JsonController";
import {Authorized, Body, Get, Post, Res} from "routing-controllers";


interface authData {
    password: string;
    username: string;
    email?: string;
}
@JsonController("/users")
export class UsersController {
    private userRepository: Repository<User>;

    constructor() {
        this.userRepository = getConnectionManager().get().getRepository(User);
    }
    @Authorized()
    @Get("/auto")
    public async checkAuthentication(@Res() res: Response) {
        res.send("Authorized");
    }

    @Post("/sign_up")
   public async   signUp(@Body() authData: authData, @Res() res: Response) {
        if (authData.username && authData.email && authData.password) {
            let user = await  this.userRepository.findOneById(authData.username);
            const count = await this.userRepository.count();
            if (!user) {
                user = new User();
                user.username = authData.username;
                user.email = authData.email;
                user = await authService.setHashedPassword(user, authData.password);
                user.admnin = count === 0;


                this.userRepository.persist(user);
                res.send(user);
            }
            else {
                res.send("Already exists");
            }
        } else {
            res.send("Incomplete");
        }
    }


    @Post("/sign_in")
   public async signIn(@Body() authData: authData, @Res() res: Response) {
        if (authData.username && authData.password) {
            let user = await  this.userRepository.findOneById(authData.username);

            if (user) {
                console.log(user);
                const valid = await authService.checkPassword(authData.password, user);
                if (valid) {
                   authService.setTokenForUser(res, user).then(() => {
                        res.send("logged in");
                    });

                } else {
                    res.send("Wrong information");
                }
            } else {
                res.send("Not found");
            }
        } else {
            res.send("Incomplete");
        }
    }


}

everything works fine. Is there something I am missing or is this a bug?

Thanks a lot, Christian

Christian24 avatar May 20 '17 18:05 Christian24

sounds strange, does it work if you remove @Authorized() decorator?

pleerock avatar May 22 '17 04:05 pleerock

No, that doesn't solve it. Only the order seems to solve it. Interestingly enough it only seems to crash in signIn. SignIn is being called though.

setTokenForUser is defined like this:

 setTokenForUser: (res: Response, user: User) => {
        return new Promise((resolve, reject) => {
            const jwtClaimSet: JWTClaimSet = { name: user.username, email: user.email };
            jwt.sign(jwtClaimSet, config.authentication.secret, { algorithm: 'HS256' },
                (err: Error, token: string) => {
                    if (err) {
                        reject('Could not create jwtToken!')
                        console.log(err);
                    } else {
                        console.log("Hello world");
                        res.cookie(config.authentication.cookiename, token);
                        console.log(token);
                        resolve();
                    }
                });
        });
    }

It seems to crash on the cookie function call. The console.log is still being executed.

Christian24 avatar May 22 '17 15:05 Christian24

This should not be possible. Can you please setup a git repo with a minimal reproduction of your problem, then I can checkout, debug and solve your problem.

pleerock avatar May 25 '17 07:05 pleerock

There you go: https://github.com/Christian24/routingcontrollersissue/tree/master

Thanks a lot.

Christian24 avatar May 26 '17 16:05 Christian24

@Christian24 Can you do a MINIMAL example? One simple controller with 2-3 simple routes, one service if needed, not the entire jungle which is hard to understand.

For me it looks like you've forgot to return promise somewhere in you hell and because of next fallthrough the next route is catched as it also match to the pattern.

MichalLytek avatar Sep 05 '17 16:09 MichalLytek

@pleerock @19majkel94 same problem here!!!

I have two endpoints on controller 'UserController'

@Get('/me')
@Get('/:userId')

both marked as @Authorized

some requests executes /:userId with 'me' as param

fernandolguevara avatar Dec 05 '18 21:12 fernandolguevara

Stale issue message

github-actions[bot] avatar Feb 17 '20 00:02 github-actions[bot]