-
-
Notifications
You must be signed in to change notification settings - Fork 163
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
Add example to server.Context.md documentation for pubsub withFilter function #272
Conversation
Added some documentation to explain how this can be used with the withFilter function of pubSub Took me ages to figure this out so thought I'd leave that knowledge here in case it helped someone else in the future
Sorry to disappoint but I wont be merging this. A few reasons:
|
All good @enisdenjo, just trying to help. Got your point about auto generated docs, makes sense. Apollo docs is where I started, the reason I was unable to get their version working was due to the fact the context was not being passed through, hence my example. It took me a long time to figure out why that was the case. But yeah fair enough, you want to keep this focused on a single task so makes sense not to scope-creep. It's interesting though that Apollo no longer supports web socket transport, and the library they recommended actually recommends this library which is how I found it. I'm curious to know if there is an alternative way to manage subscriptions back to the front-end that is not "the apollo way". I wasn't really aware of there being much gql outside of that ecosystem. Without filtering you just end up broadcasting all events to every subscriber on the front-end, which is obviously not desirable due to security etc. So if you happen to have any non-apollo libraries or resources on that I'd be super interested in those! |
@Gembot-ai-admin You can simply create your own typed EventEmitter: import { EventEmitter, on } from 'events'
type PubSubPublishArgsByKey = {
[key: string]: [any] | [number | string, any]
}
export const createChannelPubSub = <
TPubSubPublishArgsByKey extends PubSubPublishArgsByKey,
>() => {
const emitter = new EventEmitter()
return {
publish: <TKey extends Extract<keyof TPubSubPublishArgsByKey, string>>(
routingKey: TKey,
...args: TPubSubPublishArgsByKey[TKey]
) => {
if (args[1] !== undefined) {
emitter.emit(`${routingKey}:${args[0] as number}`, args[1])
}
emitter.emit(routingKey, args[0])
},
subscribe: async function* <
TKey extends Extract<keyof TPubSubPublishArgsByKey, string>,
>(
...[routingKey, id]: TPubSubPublishArgsByKey[TKey][1] extends undefined
? [TKey]
: [TKey, TPubSubPublishArgsByKey[TKey][0]]
): AsyncGenerator<
TPubSubPublishArgsByKey[TKey][1] extends undefined
? TPubSubPublishArgsByKey[TKey][0]
: TPubSubPublishArgsByKey[TKey][1]
> {
const asyncIterator = on(
emitter,
id === undefined ? routingKey : `${routingKey}:${id as number}`,
)
for await (const [value] of asyncIterator) {
yield value as any
}
},
}
} In addition you can filter with these functions: export const map = <T, O>(map: (input: T) => Promise<O> | O) =>
async function* mapGenerator(asyncIterable: AsyncIterableIterator<T>) {
for await (const value of asyncIterable) {
yield map(value);
}
};
export const filter = <T, U extends T = T>(filter: (input: T) => input is U) =>
async function* filterGenerator(asyncIterable: AsyncIterableIterator<T>) {
for await (const value of asyncIterable) {
if (filter(value)) {
yield value;
}
}
};
// you probably wanna use a pipe with type definitions from lodash or similar :)
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x); Putting all the pieces together: type PubSubChannels = {
someEvent: [string]
}
const pubSub = createChannelPubSub<PubSubChannels>()
const Subscription = new GraphQLObjectType({
name: "Subscription",
fields: {
test: {
type: GraphQLString,
subscribe: () =>
pipe(
pubSub.subscribe("someEvent"),
map(value => value.repeat(3)),
filter(value => value.length < 10)
)
}
}
}); |
Wow, thanks for the input, that's super helpful. I'm pretty sure I can get it to do what I need now. |
Added some documentation to explain how this can be used with the withFilter function of pubSub
Took me ages to figure this out so thought I'd leave that knowledge here in case it helped someone else in the future