Skip to content
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

feat(core,websockets): use rxjs to check if values are observables #9491

Merged
merged 3 commits into from May 17, 2022

Conversation

micalevisk
Copy link
Member

@micalevisk micalevisk commented Apr 23, 2022

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Other... Please describe:

What is the current behavior?

Here's the full code: https://gitlab.com/micalevisk/nestjs-observable-issue

If we return a literal object that has the subscribe method on it, the application gets stuck

import { Controller, Get, Req } from '@nestjs/common'
import { of, Observable } from 'rxjs'

@Controller()
export class AppController {
  @Get()
  getHello(): any {
    return { subscribe(){} }
  }
}

If we return req.route (from Express), we got the following error (and 500 as a response)

Error: Route.subscribe() requires a callback function but got a [object Object]
    at Route.<computed> [as subscribe] (/x/node_modules/express/lib/router/route.js:202:15)
    at /x/node_modules/rxjs/src/internal/lastValueFrom.ts:59:12
    at new Promise (<anonymous>)
    at Object.lastValueFrom (/x/node_modules/rxjs/src/internal/lastValueFrom.ts:56:10)
    at RouterResponseController.transformToResult (/x/node_modules/@nestjs/core/router/router-response-controller.js:34:27)
    at /x/node_modules/@nestjs/core/router/router-execution-context.js:174:52
    at /x/node_modules/@nestjs/core/router/router-execution-context.js:47:19
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at /x/node_modules/@nestjs/core/router/router-proxy.js:9:17
import { Controller, Get, Req } from '@nestjs/common'
import { of, Observable } from 'rxjs'
import { Request } from 'express'

@Controller()
export class AppController {
  @Get()
  getHello(@Req() req: Request): string | Observable<string> | Record<string, any> {
    // return 'hello world' // Works
    // return of('hello world') // Works
    return req.route // Errors but should work too as it isn't an Observable
  }
}

What is the new behavior?

Instead of checking if the return of the method has the function subscribe, we're using isObservable from rxjs to check if the return is, in fact, a valid observable object

Thus, now with the above code the server will reply with this JSON instead:

{
  "path": "/",
  "stack": [
    {
      "name": "<anonymous>",
      "keys": [],
      "regexp": {
        "fast_star": false,
        "fast_slash": false
      },
      "method": "get"
    }
  ],
  "methods": {
    "get": true
  }
}

as expected.

And just {} when we return { subscribe(){} }

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

There are other places in which isObservable is used. See:

image

While others are using isFunction(value.subscribe) and I'm unsure if this was intentional. See:

image

Should we do the same for

const isUpstreamSubject =
upstreamSubjectOrData && isFunction(upstreamSubjectOrData.subscribe);

const isUpstreamSubject =
upstreamSubjectOrData && isFunction(upstreamSubjectOrData.subscribe);

?

@micalevisk micalevisk closed this Apr 23, 2022
@micalevisk micalevisk reopened this Apr 23, 2022
@coveralls
Copy link

coveralls commented Apr 23, 2022

Pull Request Test Coverage Report for Build dcbc02b5-7264-47ae-ad61-0d9f89c128bd

  • 6 of 6 (100.0%) changed or added relevant lines in 2 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage decreased (-0.001%) to 94.043%

Totals Coverage Status
Change from base Build 0a7dce2a-d55f-4ed3-96fe-535d2466a616: -0.001%
Covered Lines: 5762
Relevant Lines: 6127

💛 - Coveralls

@micalevisk
Copy link
Member Author

looks like the CI pipeline is broken 🤔

@micalevisk micalevisk force-pushed the fix-use-isObservable branch 2 times, most recently from 98406df to 88575ee Compare April 23, 2022 02:41
@@ -158,7 +163,7 @@ export class WebSocketsController {
deferredResult: Promise<any>,
): Promise<Observable<any>> {
const result = await deferredResult;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw the tests didn't cover the following

image

because
await Promise.resolve( Promise.resolve(123) ) return 123 (node16)

Should we drop that if?

https://github.com/micalevisk/nest/blob/88575ee0226b418491b4186fb9bc8943a6ee253b/packages/websockets/web-sockets-controller.ts#L169-L171

@kamilmysliwiec kamilmysliwiec added this to the 9.0.0 milestone May 13, 2022
@kamilmysliwiec kamilmysliwiec changed the base branch from master to 9.0.0 May 17, 2022 11:13
@kamilmysliwiec kamilmysliwiec merged commit 19b55e9 into nestjs:9.0.0 May 17, 2022
@micalevisk micalevisk deleted the fix-use-isObservable branch May 17, 2022 11:41
@kamilmysliwiec kamilmysliwiec mentioned this pull request May 20, 2022
12 tasks
@micalevisk micalevisk changed the title Use rxjs when checking if the value is an observable feat: use rxjs to check if values are observables May 25, 2022
@micalevisk micalevisk changed the title feat: use rxjs to check if values are observables feat(core,websockets): use rxjs to check if values are observables May 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants