8

Consider the following GraphQL template:

type Foo {
  id: ID!
  bars: Bars
}

type Bar {
  id: ID!
  name: String!
}

type Bars {
  items: [Bar]!
  nextToken: String
}

The mapping template for the bars field in the Foo type looks like this:

#set($ids = [])
#foreach($id in $context.source.bars)
    #set($map = {})
    $util.qr($map.put("id", $util.dynamodb.toString($id)))
    $util.qr($ids.add($map))
#end
{
    "version" : "2018-05-29",
    "operation" : "BatchGetItem",
    "tables" : {
        "barsTable" : {
             "keys": $util.toJson($ids),
             "consistentRead": true
         }
     }
}

This works well. But if the bars field contains and empty array [], the template will obviously crash with the following error:

"errors": [
    {
      "path": [
        "getFoo",
        "bars"
      ],
      "data": null,
      "errorType": "MappingTemplate",
      "errorInfo": null,
      "locations": [
        {
          "line": 59,
          "column": 7,
          "sourceName": null
        }
      ],
      "message": "RequestItem keys '$[tables][barsTable]' can't be empty"
    }
  ]

So my question is:
How do I prevent the query to be executed and just return an empty array to the response template when $context.source.bars is empty ?

Quentin Hayot
  • 7,786
  • 6
  • 45
  • 62

3 Answers3

13

It took me hours to figure out this one. It's as simple as calling the #return(data) from the request mapper.

In your case:

#if ($context.source.bars.size() <= 0) 
   #return([])
#end

#set($ids = [])
#foreach($id in $context.source.bars)
    #set($map = {})
    $util.qr($map.put("id", $util.dynamodb.toString($id)))
    $util.qr($ids.add($map))
#end
{
    "version" : "2018-05-29",
    "operation" : "BatchGetItem",
    "tables" : {
        "barsTable" : {
             "keys": $util.toJson($ids),
             "consistentRead": true
         }
     }
}
Matej Balantič
  • 1,627
  • 18
  • 21
-1

You can use

#if(!$array.isEmpty())
   //do something
#else
  //do something else
#end

For more information you can refer the resolver mapping template reference guide here

Karthik
  • 934
  • 9
  • 21
-1

I tried to reproduce your usecase and finally I came up with one trick to solute the problem.
Example schema:

type Query {
    getTests(ids: [ID!]): [Test]
}
type Test {
    id: ID!
    title: String!
}
schema {
    query: Query
}

Solution

## REQUEST MAPPING
#set($ids = [])
## CREATE A FAKE-ID TO RETURN NULL ONLY IF ids IS NULL OR EMPTY
#if( $ctx.args.ids.isEmpty() || $util.isNull($ctx.args.ids) )
  #set($map = {})
  $util.qr($map.put("id", $util.dynamodb.toString("fake-id-to-return-null")))
  $util.qr($ids.add($map))
#else
  #foreach($id in $ctx.args.ids)
      #set($map = {})
      $util.qr($map.put("id", $util.dynamodb.toString($id)))
      $util.qr($ids.add($map))
  #end
#end

{
    "version" : "2018-05-29",
    "operation" : "BatchGetItem",
    "tables" : {
        "TestTable": {
            "keys": $util.toJson($ids),
            "consistentRead": true
        }
    }
}

## RESPONSE MAPPING
$utils.toJson($ctx.result.data.TestTable)

Another similar solution

#if( !($util.isNull($ctx.args.ids) || $ctx.args.ids.isEmpty()) ) 
    #set($ids = [])
    #foreach($id in $ctx.args.ids)
        #set($map = {})
        $util.qr($map.put("id", $util.dynamodb.toString($id)))
        $util.qr($ids.add($map))
    #end
    {
        "version" : "2018-05-29",
        "operation" : "BatchGetItem",
        "tables" : {
            "TestTable": {
                "keys": $util.toJson($ids),
                "consistentRead": true
            }
        }
    }
#else
    {
        "version": "2017-02-28",
        "operation": "GetItem",
        "key": {
            "id": $util.dynamodb.toDynamoDBJson("."),
        }
    }
#end

Testing

enter image description here

enter image description here

enter image description here

KoingDev
  • 620
  • 6
  • 12