javascript - არსებობს უკეთესი RXJs ოპერატორი, რომელიც გამოიყენება ამ სცენარში?


მე მაქვს სერვისის მეთოდი, რომელიც აკეთებს შემდეგს:

  1. ძებნის მომხმარებელს მონაცემთა ბაზაში მათი ID-ის მიხედვით
  2. ამოწმებს, პოვნა თუ მოხდა მომხმარებელი
  3. გამოყენებს bcrypt-ს, რათა შეადაროს მონაცემთა ბაზაში შენახული პაროლი, პარამეტრის სახით მიწოდებულ პაროლთან
  4. ინახავს UnauthorizedException-ს, თუ პაროლი არასწორია, აბრუნებს მომხმარებელს, თუ სწორი არის.

მე უბრალოდ ვცდი ამდენსაც გარეთ გამოსვლის გარეშე, არის თუ არა ამის უკეთ გაკეთების გზა RxJS ოპერატორების გამოყენებით, რადგან bcrypt.compare-ის pipe-ს გამოყენება არ მომწონს:

public validateUser(email: string, pass: string): Promise<UserDto> {
    return this.userService
      .findOne({ email })
      .pipe(
        map((user: UserDto) => {
          if (!user || !user.password) {
            return throwError(new UnauthorizedException());
          }
          return user;
        }),
        switchMap((user: UserDto) => {
          return from(
            bcrypt.compare(pass, user.password) as Promise<boolean>
          ).pipe(
            map((passwordIsCorrect) => ({
              passwordIsCorrect,
              user
            }))
          );
        }),
        switchMap((res) => {
          if (!res.passwordIsCorrect) {
            return throwError(new UnauthorizedException());
          }
          return of(res.user);
        })
      )
      .toPromise();
  }

უპასუხე #1

ვერ ვფიქრობ, რომ არსებობს უკეთესი ოპერატორი გამოსაყენებლად, მაგრამ შეგიძლიათ კოდი ასეთად შეაჯამოთ, რომ ყველაფერი ერთ switchMap-ში იყოს:

  public validateUser(email: string, pass: string): Promise<UserDto> {
    return this.userService.findOne({ email }).pipe(
      switchMap(user => {
        if (!user?.password) {
          return throwError(new UnauthorizedException());
        }

        return from(bcrypt.compare(pass, user.password)).pipe(
          switchMap(passwordIsCorrect => passwordIsCorrect ? of(user) : throwError(new UnauthorizedException()))
        )
      })
    ).toPromise();
  }

თუმცა, ამ შემთხვევაში, ჩანს, რომ თქვენ ბრძოლა გჭირდებათ observables-ის გამოყენებისთვის, (პრომისის კონვერტირება observable-ში, მხოლოდ იმისთვის, რომ ისევ პრომისად გადააკეთოთ).

უწლებლად თუ userService აბრუნებს observable-ს, რატომ არ გადავაქციოთ პირდაპირ promise-ად? ჩანს, რომ კოდი ბევრად მარტივი იქნება:

  public async validateUser(email: string, pass: string): Promise<UserDto> {
    const user = await this.userService.findOne({ email }).toPromise();
    
    if (!user?.password || !await bcrypt.compare(pass, user.password)) {
      throw new UnauthorizedException();
    }
    
    return user;
  }

პასუხი #2

თუ ნამდვილად არ მოგწონს შიდა მილაკი, შეგიძლიათ გამოიყენოთ combineLatest, რათა გადაეცეთ user-ის მნიშვნელობა ასევე passwordIsCorrect:

public validateUser(email: string, pass: string): Promise<UserDto> {
    return this.userService
      .findOne({ email })
      .pipe(
        map((user: UserDto) => {
          if (!user || !user.password) {
            return throwError(new UnauthorizedException());
          }
          return user;
        }),
        switchMap((user: UserDto) => {
          return combineLatest([
            from(bcrypt.compare(pass, user.password)),
            of(user)
          ])
        }),
        map(([passwordIsCorrect, user]) => ({
          passwordIsCorrect,
          user
        })),
        switchMap((res) => {
          if (!res.passwordIsCorrect) {
            return throwError(new UnauthorizedException());
          }
          return of(res.user);
        })
      )
      .toPromise();
  }