[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
For the following simple example:
@Subscription(returns => Object, {
filter: (payload: any, variables: any) => {
console.log('payload', payload);
console.log('variables', variables);
return true;
},
})
objectAdded() {
return pubSub.asyncIterator<Station>('objectAdded');
}
Got the following result:
TypeError: asyncIterator.return is not a function
Because in https://github.com/nestjs/graphql/blob/master/lib/services/resolvers-explorer.service.ts -> createSubscriptionMetadata, when filter is present the method withFilter is called with a promise as parameter instead of AsyncIterator.
No error should occur.
@Subscription(returns => Object, {
filter: (payload: any, variables: any) => {
console.log('payload', payload);
console.log('variables', variables);
return true;
},
})
objectAdded() {
return pubSub.asyncIterator<Station>('objectAdded');
}
Cannot update the project from 5.x to 6.x.
Nest version: 6.0.1
For Tooling issues:
- Node version: v10.15.0
- Platform: Mac
Others:
The project is a NX one.
Would you be interested in creating a PR? :)
Should be fixed in 6.0.2 :) Let me know if you face any issues
Hi, I installed 6.0.2 and have the same code as above. the filter function doesn't run and I don't see any error tho
I tried it too, and the initial error is not present anymore, but the filter method is not called. The result is a subscription without filter.
i got the same result #182
the filter function doesn't run
Same problem, no filter method called, but resolve function is ok
any progress?
Same problem :(
@ 6.0.2 and issue is still there
Same
Same problem
same @6.0.5
A temp resolution for Code first style subscription. You need an asyncInterator filter function:
@Subscription(returns => Media)
mediaChanged(@Context() ctx) {
return asyncFilter(
pubSub.asyncIterator('mediaChanged'),
payload => payload.mediaChanged.userId === ctx.session.id
)
}
asyncFilter implement below (pay attention it's NOT same as withFilter from 'graphql-subscriptions'):
import { $$asyncIterator } from 'iterall'
export type FilterFn<T> = (rootValue?: T) => boolean | Promise<boolean>
export const asyncFilter = <T = any>(asyncIterator: AsyncIterator<T>, filterFn: FilterFn<T>): AsyncIterator<T> => {
const getNextPromise = () => {
return asyncIterator.next().then(payload => {
if (payload.done === true) {
return payload
}
return Promise.resolve(filterFn(payload.value))
.catch(() => false)
.then(filterResult => {
if (filterResult === true) {
return payload
}
// Skip the current value and wait for the next one
return getNextPromise()
})
})
}
return {
next() {
return getNextPromise()
},
return() {
return asyncIterator.return()
},
throw(error) {
return asyncIterator.throw(error)
},
[$$asyncIterator]() {
return this
},
}
}
Same issue with 6.1.1 and a code-first resolver.
@Subscription(type => PairStatus, {
filter: (payload: PairStatus, variables: any, context: any) => {
console.log(variables);
console.log(payload);
console.log(context);
return payload.pairCode === variables.code;
},
resolve: value => {
console.log(value);
return value as any;
}
})
pairStatus(@Args({ type: () => String, name: 'code' }) code: string) {
return this.pubSub.asyncIterator('devicePaired');
}
Only the console.log inside the resolve function prints and the value seems to be the context, not the value that is being resolved. Without the resolve function, the subscription does not resolve when I publish to the PubSub.
I have the same problem on my project.
It should be fixed in the @next version ($ npm i @nestjs/graphql@next). You will also have to update @nestjs/core to 6.2.0 ($ npm i @nestjs/[email protected]). Please, let me know if you face any issue.
@kamilmysliwiec Unfortunately, subscriptions in @next version are not working at all.
Thanks for reporting @tverdohleb! Could you check 6.2.0-next.4?
@kamilmysliwiec, thanks for the update! Subscriptions basic functionality work again, but the context in the filter method is still undefined (at the same time, resolve method gots the right values).
I published 6.2.0-next.5 with a few fixes. Feel free to test whenever you have some spare time :)
Published as 6.2.0 ($ npm i @nestjs/graphql@latest). You will also have to update @nestjs/core to 6.2.0 ($ npm i @nestjs/core@latest)
@kamilmysliwiec Perfect! Works as expected! Thanks for your hard work!
Btw, what do you think about extracting types like SubscriptionFilterFn and SubscriptionResolverFn from SubscriptionOptions interface?
Context is still undefined for me, am I missing something:
https://www.screencast.com/t/ekLdIlek4NrV => https://www.screencast.com/t/PTAbTFrDaQ => https://www.screencast.com/t/1aGi5P0ct
@kamilmysliwiec I got filter payload on the latest update 6.3.1 but context is undefined, I want to pass userId for filtering through context
@Subscription(type => PairStatus, {
filter: (payload: PairStatus, variables: any, context: any) => {
console.log(variables);
console.log(payload);
console.log(context);
return payload.pairCode === variables.code;
},
resolve: value => {
console.log(value);
return value as any;
}
})
pairStatus(@Args({ type: () => String, name: 'code' }) code: string) {
return this.pubSub.asyncIterator('devicePaired');
}
GraphQLModule.forRoot({
installSubscriptionHandlers: true,
autoSchemaFile: 'schema.gql',
context: ({ req }) => ({ req }),
subscriptions: {
onConnect: async connectionParams => {
connectionParams = mapKeys(connectionParams, (value: String, key: String) => key.toLowerCase());
const authToken = get(connectionParams, 'authorization', null);
if (authToken) {
// Debug
let method = new GraphQLAuthGuard();
let token = await method.validateToken(authToken);
console.log('Token: ', token);
return token;
}
throw new AuthenticationError('authToken must be provided');
}
}
}),
EDIT#1:
Solved by amending GraphqlModule context:
context: ({ req, connection }) => ({ req, connection }),
But in Subscription I access my user this way
filter: (payload: any, variables: any, context: any) => {
let userId = context.connection.context.id;
Is this correct way ? req btw is undefined
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
A temp resolution for
Code firststyle subscription. You need an asyncInterator filter function:asyncFilterimplement below (pay attention it's NOT same aswithFilterfrom 'graphql-subscriptions'):