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.