MichalLytek / type-graphql

Create GraphQL schema and resolvers with TypeScript, using classes and decorators!

Home Page:https://typegraphql.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Subscription with subscribe require non-null return, asyncIterator yield not works

wenerme opened this issue · comments

Describe the Bug

I expected the subscription return data from subscribe async iterator.

To Reproduce

@Resolver()
@Injectable()
export class CommonResolver {

  @Subscription(() => GeneralResponseObject, {
    subscribe: async function* ({ args: { interval, count } }) {
      let n = 0;
      interval = clamp(interval, 1_000, 60_000);
      count = clamp(count, 1, 1000);
      console.log('Ticker', { interval, count });
      for (let i = 0; i < count; i++) {
        await sleep(interval);
        console.log('Tick', n);
        yield {
          message: `Tick ${n++}`,
          data: {
            count,
            now: new Date(),
          },
        };
      }
      return {
        message: 'DONE',
      };
    },
  })
  async ticker(
    @Arg('interval', () => Number, {
      nullable: true,
      defaultValue: 1_000,
    })
    interval: number,
    @Arg('count', () => Number, { nullable: true, defaultValue: 10 }) count: number,
  ) {
    // curl -N -H "accept:text/event-stream" "http://localhost:8066/graphql?query=subscription%7Bticker%7Bmessage%7D%7D"

    // fixme why can not return null ?
    return {
      message:'Start'
    }
  }
}
  • event stream return all {"data":{"ticker":{"message":"Start"}}}
  • curl will block and return for once
curl -N -H "accept:text/event-stream" "http://127.0.0.1:8066/graphql?query=subscription%7Bticker%7Bmessage%7D%7D"
:

event: next
data: {"data":{"ticker":{"message":"Start"}}}

event: next
data: {"data":{"ticker":{"message":"Start"}}}

event: next
data: {"data":{"ticker":{"message":"Start"}}}

event: next
data: {"data":{"ticker":{"message":"Start"}}}

event: next
data: {"data":{"ticker":{"message":"Start"}}}

event: next
data: {"data":{"ticker":{"message":"Start"}}}

event: next
data: {"data":{"ticker":{"message":"Start"}}}

event: next
data: {"data":{"ticker":{"message":"Start"}}}

event: next
data: {"data":{"ticker":{"message":"Start"}}}

event: next
data: {"data":{"ticker":{"message":"Start"}}}

event: complete

Expected Behavior

  • subscription can return null/undefined
  • return data in yield
  • not block, maybe caused by hono+yoga ?

Logs

Environment (please complete the following information):

  • OS: macOS
  • Node 20
  • Package version 2.0
  • TypeScript version 5.4

Additional Context

The subscription handler, the class method, is a bridge between async iterator and response. This function is responsible for parsing, checking or transforming the payload returned from the async iterator.

Please checks the docs and examples - you should use @Root() decorator to get the payload from async iterator and then you can do e.g. return payload.data.

subscription can return null/undefined

Of course it can, you just have to do this explicitly. And first of all, mark this method as nullable in @Subscription decorator option.

@MichalLytek thanks, @Root works.

Follow this doc https://typegraphql.com/docs/subscriptions.html#creating-subscriptions there , there only one example using subscribe:, for my case, I should just return root .

Is it possible to have a onsubscribe callback when using Subscription ?

e.g. I want to send a hello if subscribed

  @Subscription(() => GeneralResponseObject, {
    topics: 'PUB',
  })
  sub(@Root() root:any) {
    // curl -N -H "accept:text/event-stream" "http://localhost:8066/graphql?query=subscription%7Bsub%7Bmessage%7D%7D"

    // getPubSub().publish('PUB', { message: 'Hello' });

    return root
  }

Is it possible to have a onsubscribe callback when using Subscription ?

Wdym? I think I don't understand your question. You ask about the client? Or you want to send special message while client connects and then the values from pubsub?

@MichalLytek sory for the unclear question, I want to have a callback for client subscribed, but maybe I should do this in pubsub, thanks.