`withFilter` equivalent in Absinthe

Hi there,

I was reading through the Absinthe docs on subscriptions and I’ve been trying to figure out the Absinthe equivalent of withFilter from graphql-subscriptions.

Here’s my use case, I’m creating a chat application and using GraphQL to publish new chats as they come in from a NATS subscription. The problem is sometimes someone is abusive/bad actor so I’m building in abuse detection. I would like it so that during the mutation if we find the chat message to be abusive, we mark it as such and ONLY publish that message to the original sender and not everyone else. This way the abuser thinks it went through. But no one else sees the new message show up.

This is the code I can write in JS land:

export const resolvers = {
  Subscription: {
    newChat: {
      subscribe: withFilter(() => pubsub.asyncIterator("NEW_CHAT"), (chatMessage, vars, context) => {
        if (chatMessage.channelID !== vars.channelID) return false;
        // All users can see non-abusive messages
        if (!chatMessage.abusive) return true;
        if (
          // Allow the author to see their own abusive message
          chatMessage.authorID === context.user.id || 
          // and anyone on the same network as them (other PC open?)
          chatMessage.authorIP === context.reqIP
        ) return true;
        return false;

There doesn’t seem to be a way to do this same filtering of events in Absinthe once you subscribe to a topic. Would the Absinthe maintainers be open to an API that looked like this?

subscription do
  field :new_chat, :chat do
    arg :channel_id, non_null(:string)

    config fn args, _ ->
      {:ok, topic: "new_chat:#{args.channel_id}"}

    filter fn chatMessage, args, context, _ ->
      cond do
        !chatMesssage.abusive -> :ok
        chatMessage.author_id == context.user.id -> :ok
        chatMessage.author_ip == context.req_ip -> :ok
        true -> :skip


Where filter takes a function/4 that has payload, arguments, context, info and returns either :ok to process the event or :skip to skip the publishing of the subscription event. If so, would someone be able to point me where to take a look in the code? I’m happy to take the first crack at it with a PR.


1 Like