3

I am trying to send a POST body to a AWS Lambda function using the iOS (Swift) SDK generated by AWS API GATEWAY, but the transmitted body is always empty.

To do so I set up a model:

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "InputModel",
    "type": "object",
    "required" : ["name"],
    "properties": {
        "name": { "type": "string" },
    }
}

,which I included in the $Resources -> /test -> POST -> Method Execution -> Method Request -> Request Body panel.

Then I deployed the API and downloaded and included the API Gateway generated SDK. Now I am calling the API (as recommended in Use Generated iOS SDK (Swift) to Call API) like so:

let apiClient = APITestClient.default()
let body = APITest()
body!.name = "HOLA"

apiClient.testPost(body: body!).continueWith { task -> Void in ... }

But the body my Lambda function receives is always empty {}, which I checked in the API Gateway logs:

(c421a895-b0c7-11e7-89a6-891dcbadf1f0) Method request body before transformations:
{}

and the Lambda function Logs:

2017-10-14T10:09:29.418Z    c424b611-b0c7-11e7-99c1-251bdb6a1eac    Request:
{
    "resource": "/test",
    "path": "/test",
    "httpMethod": "POST",
    "headers": {
        "Accept": "application/json",
        "Accept-Encoding": "br, gzip, deflate",
        "Accept-Language": "en-us",
        "CloudFront-Forwarded-Proto": "https",
        "CloudFront-Is-Desktop-Viewer": "true",
        "CloudFront-Is-Mobile-Viewer": "false",
        "CloudFront-Is-SmartTV-Viewer": "false",
        "CloudFront-Is-Tablet-Viewer": "false",
        "CloudFront-Viewer-Country": "ES",
        "content-type": "application/json",
        "Host": "9hlt8n48wd.execute-api.eu-west-1.amazonaws.com",
        "User-Agent": "aws-sdk-iOS/2.6.4 iOS/11.0 en_US",
        "Via": "2.0 9ee2752d23ce7be13204dc3880c3ca6b.cloudfront.net (CloudFront)",
        "X-Amz-Cf-Id": "39uT89_umng7zPCNHqn3WdLlNJ6zFbQ5fmLVzJJNFcud-7pdZYJ1mg==",
        "X-AMZ-Date": "20171014T100929Z",
        "x-amz-security-token": "---",
        "X-Amzn-Trace-Id": "---",
        "X-Forwarded-For": "---",
        "X-Forwarded-Port": "443",
        "X-Forwarded-Proto": "https"
    },
    "queryStringParameters": null,
    "pathParameters": null,
    "stageVariables": null,
    "requestContext": {
        "path": "/production/test",
        "accountId": "037641059503",
        "resourceId": "hfza9c",
        "stage": "production",
        "requestId": "---",
        "identity": {
          ---
        },
        "resourcePath": "/test",
        "httpMethod": "POST",
        "apiId": "---"
    },
    "body": "{}",
    "isBase64Encoded": false
}

Why is the body always empty? Do I have to initialize the body different than I do? Or is there another stage where the body is cleared?


Edit: I am still struggling, but invoking the normal AWS iOS SDK:

let apiClient = APITestClient.default()
let apiGatewayRequest = AWSAPIGatewayRequest(httpMethod: "POST", urlString: "/test", queryParameters: nil, headerParameters: nil, httpBody: ["name":"example"])
apiClient.invoke(apiGatewayRequest).continueWith { task -> Void in ... }

works perfectly fine. Why does AWS even bother with generating a special API Gateway SDK?!


Edit 2: The API model

public class APITest : AWSModel {

    var example: String?

    public override static func jsonKeyPathsByPropertyKey() -> [AnyHashable : Any]!{
        var params:[AnyHashable : Any] = [:]
        params["name"] = "name"

        return params
    }
}

which is then called by

   public func testPost() -> AWSTask<APITest> {
        let headerParameters = [
                   "Content-Type": "application/json",
                   "Accept": "application/json",

                ]

        let queryParameters:[String:Any] = [:]

        let pathParameters:[String:Any] = [:]

        return self.invokeHTTPRequest("POST", urlString: "/test", pathParameters: pathParameters, queryParameters: queryParameters, headerParameters: headerParameters, body: nil, responseClass: APITest.self) as! AWSTask<APITest>
    }
DrDirk
  • 1,937
  • 3
  • 25
  • 36

6 Answers6

4

I had to manually add the @objcMembers attribute to the generated parameters model class:

@objcMembers public class MyParamsModel : AWSModel

masty
  • 1,539
  • 1
  • 17
  • 20
1

The body of my request was also showing as empty, I needed to include:

Content-Type:application/json

In the request header

blomster
  • 768
  • 2
  • 10
  • 27
0

Based on the documentation you got a typo in your AWSAPIGatewayRequest,

AWSAPIGatewayRequest(httpMethod: "POST", urlString: "/test", queryParameters: nil, headerParameters: nil, HTTPBody: ["name":"example"])

Reference:

http://docs.aws.amazon.com/AWSiOSSDK/latest/Classes/AWSAPIGatewayRequest.html#//api/name/initWithHTTPMethod:URLString:queryParameters:headerParameters:HTTPBody:

Hope it helps.

Kannaiyan
  • 12,554
  • 3
  • 44
  • 83
0

in the API Console : enter image description here

if you click on integration request :

enter image description here

make sure that the parameters you want your lambda to consume to be specified as in the screenshot. hope it helps !

OUMOUSS_ELMEHDI
  • 499
  • 5
  • 16
0

If you are using mapping templates then please make sure you add "input" property and set it to request-body you want to send in string format.

{
"input": "$util.escapeJavaScript($input.json('$'))"
}

Same issue I was facing when I was trying to set input request body from apigateway to step function and when I set up as per AWS docs(like you are trying above) it always sent empty request body. but when I set request body in "input" property, it was sent to request body in JSON format to my step function.

0

I found out that AWS only sends requests using "Content-Type: text/plain", and it worked here ;)