aws-amplifyvelocityaws-appsyncvtlaws-appsync-resolver

How can I filter a subscription using a custom resolver


I am working on a messaging app using AWS AppSync.

I have the following message type...

type Message
    @model
    @auth(
        rules: [
            { allow: groups, groups: ["externalUser"], operations: [] }
        ]
    ) {
    id: ID!
    channelId: ID!
    senderId: ID!
    channel: Channel @connection(fields: ["channelId"])
    createdAt: AWSDateTime!
    text: String
}

And I have a subscription onCreatemessage. I need to filter the results to only channels that the user is in. So I get a list of channels from a permissions table and add the following to my response mapping template.

$extensions.setSubscriptionFilter({
    "filterGroup": [
        {
           "filters" : [
                {
                    "fieldName" : "channelId",
                    "operator" : "in",
                    "value" : $context.result.channelIds
                }
           ]
        }
    ]
})

$util.toJson($messageResult)

And it works great. But if a user is in more than 5 channels, I get the following error.

{
    "message": "Connection failed: {"errors":[{"message":"subscription exceeds maximum value limit 5 for operator `in`.","errorCode":400}]}"
}

I am new to vtl. So my question is, how can I break up that filter in to multiple or'd filters?


Solution

  • According to Creating enhanced subscription filters, "multiple rules in a filter are evaluated using AND logic, while multiple filters in a filter group are evaluated using OR logic".

    Therefore, as I understand it, you just need to split $context.result.channelIds into groups of 5 and add an object to the filters array for each group.

    Here is a VTL template that will do this for you:

    #set($filters = [])
    
    #foreach($channelId in $context.result.channelIds)
      #set($group = $foreach.index / 5)
      
      #if($filters.size() < $group + 1)
        $util.qr($filters.add({
              "fieldName" : "channelId",
              "operator" : "in",
              "value" : []
          }
        ))
      #end
    
      $util.qr($filters.get($group).value.add($channelId))
    #end
    
    $extensions.setSubscriptionFilter({
        "filterGroup": [
            {
               "filters" : $filters
            }
        ]
    })
    

    You can see this template running here: https://mappingtool.dev/app/appsync/042769cd78b0e928db31212f5ee6aa17

    (Note: The Mapping Tool errors on line 15 are a result of the $filters array being dynamically populated. You can safely ignore them.)