POST url encoded form to Amazon API Gateway

15,938

Solution 1

Try to set mapping template as following:

{
  "body" : $input.json('$')
}

This would convert you string into json and pass to lambda.

From amazon docs: $input.json(x) function evaluates a JSONPath expression and returns the results as a JSON string.

Solution 2

This is not entirely related, but if you are new to Amazon API Gateway, one additional step I did not know was required was to (re) deploy your API after adding the mapping template as others have suggested (in the case you had previously deployed your API). This cost me a bunch of debugging time as I did not understand why I was continuing to get this error even after making the suggestions posted here.

If using the AWS Console,

  • navigate to any pane within your API
  • Select Actions menu at the top
  • Select Deploy API from the menu, choose the relevant stage and confirm

Solution 3

The mapping template to make form data work is pretty complicated. Here is a gist: https://gist.github.com/ryanray/668022ad2432e38493df

Also, you can see this post I wrote that has an example of how to integrate with Slack(their hooks send a POST as form data to API Gateway): http://www.ryanray.me/serverless-slack-integrations

Solution 4

In the API Gateway, select the POST method for your resource, select Integration Request and create a new Mapping Template for application/x-www-form-urlencoded:

#set($body = $input.path('$'))
#set($jsonString = $util.urlencode($body))
#set($json = $util.parsejson($jsonString))

{
  "body" : $json,
}

Alternatively, you can simply pass the url encoded string:

#set($body = $input.path('$'))
{
  "body" : "$body",
}

and url decode and parse the JSON in your lambda.

Share:
15,938
Jonas Fagundes
Author by

Jonas Fagundes

Updated on June 08, 2022

Comments

  • Jonas Fagundes
    Jonas Fagundes almost 2 years

    I'm creating a webhook to receive notifications from a 3rd-party service, they sent the data in the body of a POST with content type application/x-www-form-urlencoded.

    But it generates the same error:

    {"message": "Could not parse request body into json: Unrecognized token \'name\': was expecting \'null\', \'true\', \'false\' or NaN\n at [Source: [B@456fe137; line: 1, column: 6]"}
    

    I could reproduce the error with the following curl call:

    % curl -v -X POST -d 'name=Ignacio&city=Tehuixtla' https://rl9b6lh8gk.execute-api.us-east-1.amazonaws.com/prod/mandrillListener
    *   Trying 54.230.227.63...
    * Connected to rl9b6lh8gk.execute-api.us-east-1.amazonaws.com (54.230.227.63) port 443 (#0)
    * TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    * Server certificate: *.execute-api.us-east-1.amazonaws.com
    * Server certificate: Symantec Class 3 Secure Server CA - G4
    * Server certificate: VeriSign Class 3 Public Primary Certification Authority - G5
    > POST /prod/mandrillListener HTTP/1.1
    > Host: rl9b6lh8gk.execute-api.us-east-1.amazonaws.com
    > User-Agent: curl/7.43.0
    > Accept: */*
    > Content-Length: 27
    > Content-Type: application/x-www-form-urlencoded
    >
    * upload completely sent off: 27 out of 27 bytes
    < HTTP/1.1 400 Bad Request
    < Content-Type: application/json
    < Content-Length: 180
    < Connection: keep-alive
    < Date: Thu, 28 Jan 2016 12:29:40 GMT
    < x-amzn-RequestId: cd4d9232-c5ba-11e5-a158-b9b39f0b0599
    < X-Cache: Error from cloudfront
    < Via: 1.1 1915b8b49d2fbff532431a79650103eb.cloudfront.net (CloudFront)
    < X-Amz-Cf-Id: cxU2_b5DzIw4M_n3hJBFXTu9AVRBL3GpbQqUId9IxgS004DfLYqYmg==
    <
    * Connection #0 to host rl9b6lh8gk.execute-api.us-east-1.amazonaws.com left intact
    {"message": "Could not parse request body into json: Unrecognized token \'name\': was expecting \'null\', \'true\', \'false\' or NaN\n at [Source: [B@d92973b; line: 1, column: 6]"}
    

    If I wrap the body with double-quotes it works fine:

    % curl -v -X POST -d '"name=Ignacio&city=Tehuixtla"' https://rl9b6lh8gk.execute-api.us-east-1.amazonaws.com/prod/mandrillListener
    *   Trying 54.230.227.19...
    * Connected to rl9b6lh8gk.execute-api.us-east-1.amazonaws.com (54.230.227.19) port 443 (#0)
    * TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    * Server certificate: *.execute-api.us-east-1.amazonaws.com
    * Server certificate: Symantec Class 3 Secure Server CA - G4
    * Server certificate: VeriSign Class 3 Public Primary Certification Authority - G5
    > POST /prod/mandrillListener HTTP/1.1
    > Host: rl9b6lh8gk.execute-api.us-east-1.amazonaws.com
    > User-Agent: curl/7.43.0
    > Accept: */*
    > Content-Length: 29
    > Content-Type: application/x-www-form-urlencoded
    >
    * upload completely sent off: 29 out of 29 bytes
    < HTTP/1.1 200 OK
    < Content-Type: application/json
    < Content-Length: 6
    < Connection: keep-alive
    < Date: Thu, 28 Jan 2016 12:33:20 GMT
    < x-amzn-RequestId: 50610606-c5bb-11e5-b140-5d837ffe26ed
    < X-Cache: Miss from cloudfront
    < Via: 1.1 a670cda0e28541e40881b95b60c672b7.cloudfront.net (CloudFront)
    < X-Amz-Cf-Id: mCLKL4eOnpUMd15IXQZw0RStJHw9Vdf3ivdCl37dcmno2JFOfxw0Vg==
    <
    * Connection #0 to host rl9b6lh8gk.execute-api.us-east-1.amazonaws.com left intact
    "true"%
    

    The lamba has only one line:

    context.succeed('true');
    

    How can I make the api gateway do not treat the body as json?

    I tried the documentation about template mapping with no success, I even tried to convert it to a static template, with no variables at all! In all cases the error happens before getting to my code.

  • Ryan Walls
    Ryan Walls over 7 years
    This is the only template that worked for me when I was sending an email address in the form. Thanks!
  • jfredys
    jfredys over 7 years
    As @hayduke replied, it is important to Deploy the API after this change to see it applied.
  • droidlabour
    droidlabour over 6 years
    @jfredys +1 +1 +1 +1 I was completely missing the deployment after changing the mapping template. Wasted two days.
  • Jim
    Jim almost 6 years
    This is not a working solution. First of all, there is no mention of where in AWS you go to change "body mapping template". Secondly, when I add this to my project I get the response, {"statusCode":502,"body":"","headers":{}} and errors in cloudwatch, ERROR: aws-serverless-express connection error and Error: socket hang up.
  • arqam
    arqam over 5 years
    How will you get the url for checking if you didn't deploy
  • hayduke
    hayduke about 5 years
    I think my comment was only relevant if you had previously deployed a version of your API (and thus had a URL). It's necessary to re-deploy. Perhaps that would be more clear.