skip to Main Content

I want to parse ‘statusCode’ and ‘body’ values from API Gateway integration response using VTL and return those as a method response like this:

Request status: 201
Response body: {"firstName":"He","lastName":"Man","email":"[email protected]"}

My API Gateway Step Function integration is returning the following integration response body (this is before transformation, non-relevant attributes are removed from output):

{
  "output": "{"statusCode":201,"body":{"firstName":"He","lastName":"Man","email":"[email protected]"}}"
}

I would assume this to work:

#set ($output = $util.parseJson($input.json('$.output')))
#set ($statusCode = $output.statusCode)
#set ($context.responseOverride.status = $statusCode)
$output.body

But status is not updated and body is empty

Request status: 200
Response body: <empty>

With this approach I can parse the body:

#set ($bodyObj = $util.parseJson($input.body))
#set ($output = $util.parseJson($bodyObj.output))
#set ($context.responseOverride.status = $output.statusCode)
$output.body

statusCode is updated but body is returned as object representation i.e. not JSON.

Request status: 201
Response body: {firstName=He, lastName=Man, [email protected]}

How to serialize $output.body correctly to JSON in above case? API Gateway doesn’t seem to have $util.toJson function like AppSync does (https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-programming-guide.html)

I’ve confirmed parsing output-variable works correctly:

#set ($output = $util.parseJson($input.json('$.output')))
$output
Request status: 200
Response body: {"statusCode":201,"body":{"firstName":"He","lastName":"Man","email":"[email protected]"}}

Relevant reference documentation:

2

Answers


  1. I ran into this exact issue. There indeed does not seem to be a way to convert to JSON directly, so I devised a way to write JSON to the API Gateway response using Apache VTL:

    #set ($outputObj = $util.parseJson($input.path('$.output')))
    #foreach ( $key in $outputObj.body.keySet() )
      "$key": $outputObj.body[$key] #if ($foreach.hasNext),#end
    #end
    

    Hope this helps!

    (This works for a simple use case like the one you described, but doesn’t generalize to nested objects, etc.)

    Login or Signup to reply.
  2. I ran into this same issue. This is how I solved it in the end. The solution provided by @noahtk7 was good for simple object, I have large nested object I needed.

    For this to work you need to have your body returned as a base64 encoded string. This is easy to do in a step function. E.G:

    "Pass": {
      "Type": "Pass",
      "Next": "Success",
      "Parameters": {
        "Base64.$": "States.Base64Encode(States.JsonToString($.Response.Body))"
      },
      "ResultPath": "$.Response.Body"
    }
    

    Then in the api response mapper:

    #set($output = $util.parseJson($input.path('$.output')))
    #set($context.responseOverride.status = $output.Response.Status)
    
    $util.base64Decode($output.Response.Body.Base64)
    

    Would give me a result of:

    {
        "foo": "bar",
        "Id": "c2b2220c-00e3-4499-87c0-d06ea5e5f1f4"
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search