ERROR [ExceptionsHandler] no elements in sequence after upgrading to NestJS v8 and RxJS v7
Asked Answered
T

1

6

After upgrading to NestJS v8, I had to upgrade my RxJS version as well from 6 to 7 then it started throwing ERROR [ExceptionsHandler] no elements in sequence error.

This is a sample method in one of the app services:

  show(): Observable<any> {
    return from(this.repository.fetch()).pipe(
      filter((data) => data.length > 0),
      map((data) => data.map((datum) => parseData(datum)),
    );
  }

While I had NestJS v7 and RxJS v6, the method was working just fine; in other words, if the filter operation is not passed, the map operator wouldn't be called at all and the Observable stops there.

But after upgrading to NestJS v8 and RxJS v7, if my repository does not return any data, the app starts throwing ERROR [ExceptionsHandler] no elements in sequence error.

A workaround I came up with is as follows:

  show(): Observable<any> {
    return from(this.repository.fetch()).pipe(
      filter((data) => data.length > 0),
      defaultIfEmpty([]),
      map((data) => data.map((datum) => parseData(datum)),
    );
  }

This way the error is gone but I have two more problems:

1- the map operator still runs which I do not want

2- the second one which is way more important to me is that I have to update all my services/methods which have a validation like this which is really crazy.

my dependencies are as follows:

 "dependencies": {
    "@nestjs/common": "^8.4.2",
    "@nestjs/core": "^8.4.2",
    "rxjs": "^7.5.5"
  },
Transform answered 24/3, 2022 at 18:28 Comment(5)
I've seen that error before when using the first() operator, if the subscription is completed without having emitted a value. Are you using first anywhere?Byers
Nest uses lastValueFrom under the hood. If there's no value emitted then there will be a problem. Try moving the defaultIfEmpty to below the map operatorNorvin
@Byers no not at allTransform
@JayMcDoniel it works the way you said. My question: Has NestJS v8 started using lastValueFrom? One more question: Isn't there a way without adding defaultIfEmpty because this way I have to update the whole source code to stop getting 500 errors. Any workaround?Transform
Nest 8 upgraded to RxJS v7 which deprecated toPromise which is why we changed to lastValueFrom. Instead of adding this to every service you could add it to an interceptor and have the interceptor set the defaultIfEmpty for youNorvin
N
5

We determined on Discord that an interceptor could be used here to set the defaultIfEmpty like so:

import {
  CallHandler,
  ExecutionContext,
  Injectable,
  NestInterceptor
} from '@nestjs/common'
import { defaultIfEmpty } from 'rxjs/operators'

@Injectable()
export class DefaultIfEmptyInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler) {
    return next.handle().pipe(defaultIfEmpty([]))
  }
}

And then bind it globally in the providers part of the module with:

import { DefaultIfEmptyInterceptor } from '../defaultIfEmpty.interceptor'
import { APP_INTERCEPTOR } from '@nestjs/core'
// ...

{
  provide: APP_INTERCEPTOR,
  useClass: DefaultIfEmptyInterceptor,
}
Norvin answered 24/3, 2022 at 19:55 Comment(2)
I'm brand new to NextJs/RxJs but seems like a bad idea to assume all endpoints will return [] if empty? What about ones that return objects?Zincograph
Then defaultIfEmpty({}). You could use metadata via a decorator to set the default and retrieve it dynamically.Norvin

© 2022 - 2024 — McMap. All rights reserved.