Search code examples
amazon-web-servicesgraphqlaws-appsyncapache-velocity

How to manipulate strings and array in Apache Velocity request mapping template in AWS appSync


This is my first time working with VTL, so please correct my code if there is something very silly in it.

What I want to achieve

{
    "cities": ["jaipur", "mumbai", "delhi", "sheros", "jalandhar", "bengaluru"]
}

Graphql schema:

type Query{
  getCitiesForGroups: String
}

Default response template:

#if($ctx.error)
    $utils.error($ctx.error.message, $ctx.error.type)
#end
    $utils.toJson($utils.rds.toJsonObject($ctx.result)[0])

Using the default response template, the result I was getting

{ "data": { "getCitiesForGroups": [ "{groupcity=jaipur}", "{groupcity=mumbai}", "{groupcity=delhi}", "{groupcity=sheros}", "{groupcity=jalandhar}", "{groupcity=bengaluru}" ] } }

My request template

{
    "version": "2018-05-29",
    "statements": [
        "select DISTINCT LOWER(city) as city from public.Groups"
    ]
}

To get the desired output, I changed the response template as I wanted to loop over the response I got from the DB, and remove the {city=} from the string by using the substring method given in AWS resolver mapping docs and this is where I am facing the problem.

My response template

#if($ctx.error)
    $utils.error($ctx.error.message, $ctx.error.type)
#end
#set ($rawListOfCities = $utils.rds.toJsonObject($ctx.result)[0])
#set ($sanitisedListOfCities = [])
#foreach( $city in $rawListOfCities )
    #set ($equalToIndex = $city.indexOf("="))
    #set ($equalToIndex = $equalToIndex + 1)
    #set ($curlyLastIndex = $city.lastIndexOf("}"))
    #set ($tempCity = $city.substring($equalToIndex, $curlyLastIndex))
    ## #set ($tempCity = $city)
    $util.qr($sanitisedListOfCities.add($tempCity))
#end
$util.toJson($sanitisedListOfCities)

The response that I am getting:

{
  "data": {
    "getCitiesForGroups": "[null, null, null, null, null, null]"
  }
}

However, when I use the line #set ($tempCity = $city) and comment out the line above it, I get the following response:

{
  "data": {
    "getCitiesForGroups": "[{city=jaipur}, {city=mumbai}, {city=delhi}, {city=sheros}, {city=jalandhar}, {city=bengaluru}]"
  }
}

Which means $city has the value {city=jaipur}, so which I want to sanitize and add it to ($sanitisedListOfCities) and return it as the response.

But I am getting null as the result substring method.

So how can I sanitize the response from DB and return it?


Solution

  • I had a similar issue and this is how I solved it.

    First, your Graphql schema should look like,

    type Query {
        getCitiesForGroups: cityList
    }
    
    type cityList {
        cities: [String]
    }
    

    Your request mapping template,

    {
        "version": "2018-05-29",
        "statements": [
            "select DISTINCT LOWER(city) as city from public.Groups"
        ]
    }
    

    And finally your response mapping template

    #set($cityList = [])
    #set($resMap = {})
    #if($ctx.error)
        $utils.error($ctx.error.message, $ctx.error.type)
    #end
    
    #foreach($item in $utils.rds.toJsonObject($ctx.result)[0])
        $util.qr($cityList.add($item.city))
    #end
    $util.qr($resMap.put("cities", $cityList))
    
    #return($resMap)
    

    Expected response(complete)

    {
      "data": {
        "getCitiesForGroups": {
          "cities": [
            "jaipur",
            "mumbai",
            "delhi",
            "sheros",
            "jalandhar",
            "bengaluru"
          ]
        }
      }
    }
    

    I hope this helps you.