30

I have been trying for a few days to get a parameter sent from the API Gateway in AWS to a Lambda function and I am having no success.

I decided to start from the beginning so I followed their walkthrough (http://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started.html#getting-started-new-lambda)

I have checked this walkthrough twice and I have followed the steps to the letter.

Problem

When I test the API from Postman or in Swift I am getting the error:

{"message": "Could not parse request body into json: Unexpected character (\'-\' (code 45)) in numeric value: expected digit (0-9) to follow minus sign, for valid numeric value\n at [Source: [B@c036d15; line: 1, column: 3]"}

In postman, When I view the result as JSON I just get

Bad String

Lambda Function

The function is the basic example from the Walkthrough:

console.log('Loading event');

exports.handler = function(event, context) {
  var name = (event.name === undefined ? 'No-Name' : event.name);
  console.log('"Hello":"' + name + '"');
  context.done(null, {"Hello":name}); // SUCCESS with message
};

When Tested from the Lambda Console and with the Test data I get the result:

{
    "Hello": "TestUser123"
}

When Tested from the API Gateway Test, The result is also:

 {
    "Hello": "TestUser123"
}

Can anyone see why both test consoles are allowing this work but when tested with POSTMAN or used within a Swift Script it does not work ?

Edit 1

In postman, I have set the content-type to application/json

The script returns the default:

 {
    "Hello": "user"
}

However, When I add in the parameters name and TestUser123 in POSTMAN, this is when it returns the error.

Update 1

Ok, so I changed the mapping template to one that I found on another answer:

{ "name": "$input.params('name')" }

Now the result is:

{
   "Hello": ""
}

Any Ideas why it is not getting the name?

Jedi
  • 3,088
  • 2
  • 28
  • 47
JamesG
  • 1,552
  • 8
  • 39
  • 86

5 Answers5

14

I just got stuck with this today.

your mapping template is:

{ "name": "$input.params('name')" }

AWS uses AWS Velocity templates, which; even though looks like JSON, is different.

if you use

{ "name": $input.params('name') } // notice no quotes

for the mapping template right at the integration request step, then it should work as expected.

Amresh Venugopal
  • 9,299
  • 5
  • 38
  • 52
  • @ARUNBALANNV can you add to this question your details so that I can see what is wrong? – Amresh Venugopal Sep 02 '16 at 14:16
  • @AmreshVenugopal What exactly is the raw output of `$input.params('name')`? – nu everest Sep 15 '16 at 21:44
  • If your request params have a query param named 'name' `?name=text` for a template `"name":input.params('name')` the name property will be set to the value of name, here `text`. Default API Gateway behaviour is to pass the request objects as-is if they don't match a template, hence you might not notice any difference. – Amresh Venugopal Sep 16 '16 at 05:19
  • very valuable info, saved my day – Serhii Kushchenko Nov 06 '21 at 10:07
5

Read the error message very carefully, it actually tells you the problem. For example, I got

Could not parse request body into json: Unexpected character (\'\"\' (code 34)): was expecting comma to separate Object entries

So the problem is that I'm missing a comma. I check my Lambda's Integration Request - Body Mapping Template:

{
"age" : $input.json('$.persondata.age'),
"income" : $input.json('$.persondata.income')
"height" : $input.json('$.persondata.height')
}

Can you spot the problem? I am missing a comma after the income line.


Here is another example.

Could not parse request body into json: Unexpected character (\'}\' (code 125)): expected a value

When I look at the Integration Request - Body Mapping Template:

#set($inputRoot = $input.path('$'))
{
  "age" : $inputRoot.age,
  "height" : $inputRoot.height,
  "income" : $inputRootincome
}

Can you spot the problem? I am missing a dot in $inputRootincome.

Jeremy Thompson
  • 61,933
  • 36
  • 195
  • 321
5

Error Message :

Could not parse request body into json: Could not parse payload into json: Unrecognized token \' \': was expecting (\'true\', \'false\' or \'null\')

Cause of the error : When string values inside the json are not assigned using double quotations in the aws mapping template the error occurs.

Solution : (Please Note : This example is for application/json type request template)

Actually the solution for the problem is, if you are using a value of type string in json then its value should be assigned inside a ("" - double quotation marks) in the mapping template.

The below shown example has the following attributes :

customerId - string (Please note : this value comes from a query parameter)
customerName - string
customerAge - integer
isPermanentEmployee - boolean
customerAddress - string (Please note this is an optional parameter)

And the mapping template should be defined like the example shown below

Refer the example below :

#set($inputRoot = $input.path('$'))
{
  "CustomerId": "$input.params('customerId')",
  "CustomerName": "$inputRoot.customerName",
  "CustomerAge": $inputRoot.customerAge,
  "IsPermanentEmployee": $inputRoot.isPermanentEmployee
  "CustomerAddress ": #if($inputRoot.customerAddress == "") "" #elseif($inputRoot.customerAddress != "") "$inputRoot.customerAddress" #end
}

If you note the above mapping template, I would have given string values inside double quotation marks("") which will solve the error

Also this example contains how to handle optional parameters in aws mapping templates using #if#else statements.

Ruli
  • 2,592
  • 12
  • 30
  • 40
Ashwin
  • 51
  • 1
  • 1
2

It is likely that you had copy-pasted multiple lines in your "Integration Request" in the API gateway.

When copying a line and pasting it below, you might have copied the hidden character '\n' at the end of that line. This is probably causing issues at the lambda function.

Example: Copying the line containing age and pasting it twice and modifying them to have height and income respectively.

#set($inputRoot = $input.path('$'))
{
  "age" : $inputRoot.age,
  "height": $inputRoot.height,
  "income": $inputRoot.income
}

Instead of copy-pasting, just type the line out for height and income.

Gru
  • 817
  • 13
  • 20
1

I ran into this issue today, it was because I had binary media type set to */* in my API settings.

enter image description here