title: How to invoke my AWS API Gateway REST API in my iOS / Swift project
body: <p>I created a Single View Application <a href="https://developer.apple.com/library/archive/referencelibrary/GettingStarted/DevelopiOSAppsSwift/BuildABasicUI.html" rel="nofollow noreferrer">in Xcode</a>, and then I followed the AWS Amplify iOS SDK guide to insert authentication using my existing Cognito User Pool. Worked beautifully.</p>
  
  <p>Then, using AWS Amplify, I <a href="https://aws-amplify.github.io/docs/ios/api" rel="nofollow noreferrer">added a REST API</a> to allow my iOS app to access a pre-existing DynamoDB table via an Amplify-generated API Gateway and a Lambda function. I had to re-wire everything, however, to use my pre-existing Cognito User Pool, because Amplify CLI unexpectedly created a new User Pool linked to the REST API it created.</p>
  
  <p>I'm getting the following error when trying to invoke my API, and no matter what I do I cannot make it go away:</p>
  
  <pre><code>Optional("{\"message\":\"Authorization header requires \'Credential\' parameter. 
  Authorization header requires \'Signature\' parameter. Authorization header requires 
  \'SignedHeaders\' parameter. 
  Authorization=abJarWQiOiJyR0NiTHFsbVwvbWdGeXgzcVA1YmNRaV...
  403
  </code></pre>
  
  <p><strong>UPDATE 5</strong>
  For more gory details, please see my <a href="https://github.com/aws-amplify/aws-sdk-ios/issues/1233" rel="nofollow noreferrer">Amplify AWS iOS SDK issue</a>. :)</p>
  
  <p><strong>UPDATE 4</strong>
  This update takes precedence over my earlier updates because it now seems clear&mdash;as the error above suggests&mdash;that I am not properly calling my REST API via the authenticated Cognito user of my iOS app. I noticed that Amplify created a User Pool with <em>two</em> App Clients, one for Web access and one for mobile access. My pre-existing User Pool only had one App Client tailored for Web access. So I created a new App Client for mobile access, with an App Client Secret.</p>
  
  <p>Unfortunately, I get the same exact error. So I'm wondering if something else needs to be re-wired; or perhaps I have a token issue. As I mentioned in the comment down below, maybe I shouldn't be using an OIDC token as specified in the REST API guide? Maybe I should use <a href="https://aws-amplify.github.io/docs/ios/authentication#managing-security-tokens" rel="nofollow noreferrer">AWS Credentials</a>? <strong>END UPDATE 4</strong></p>
  
  <p>My API has one resource <code>/items</code> and I have an <code>ANY</code> and an <code>OPTIONS</code> method. The <code>ANY</code> method does not have any URL Query String Parameters specified for the Method Request. But it does have <code>RequestSchema</code> specified of type <code>application/json</code> for the Request Body.</p>
  
  <p>My API invocation function is exactly that <a href="https://aws-amplify.github.io/docs/ios/api#iam-authorization" rel="nofollow noreferrer">specified in the AWS Amplify iOS SDK for the REST API</a> (I followed their instructions for invoking my API Gateway endpoint with Cognito User Pools authorizer), except that I changed <code>httpMethodName</code> from <code>POST</code> to <code>GET</code> because POST caused a crash. Here's what it looks like:</p>
  
  <pre><code>func doInvokeAPI(token:String) {
          // change the method name, or path or the query string parameters here as desired
          let httpMethodName = "GET"
          // the guid is the partition key for the DynamoDB table
          let URLString = "/items/178dc797-4e3d-5bc4-815f-a280536fcd3a"
          //let queryStringParameters = ["key1":"{value1}"]
          let headerParameters = [
              "Content-Type": "application/json",
              "Accept": "application/json",
              "Authorization": token
          ]
  
          //let httpBody = "{ \n  " +
          //    "\"key1\":\"value1\", \n  " +
          //    "\"key2\":\"value2\", \n  " +
          //    "\"key3\":\"value3\"\n}"
  
  
          // Construct the request object
          let apiRequest = AWSAPIGatewayRequest(httpMethod: httpMethodName,
                                                urlString: URLString,
                                                queryParameters: nil,
                                                headerParameters: headerParameters,
                                                httpBody: nil)
  
  ...
  ...
          invocationClient.invoke(apiRequest).continueWith { (task: AWSTask) -&gt; Any? in
              if let error = task.error {
                  print("Error occurred: \(error)")
                  // Handle error here
                  return nil
              }
  
              // Handle successful result here
              let result = task.result!
              let responseString = String(data: result.responseData!, encoding: .utf8)
  
              print(responseString as Any)
              print(result.statusCode)
  
              return nil
          }
      }
  </code></pre>
  
  <p>The error given above is printed by that <code>print(responseString)</code>.</p>
  
  <p>My DynamoDB table is expecting: a partition key of <code>userId</code>. A Guid String.</p>
  
  <p>I'm pretty sure all I want to pass the API is a single <code>userId</code> so that the API can retrieve all items associated with it. No need for my sort key.</p>
  
  <p>Is there a problem with how I am making this GET request via the API Gateway REST API?</p>
  
  <p><strong>UPDATE 1</strong>
  There are two JavaScript files associated with my Lambda function: <code>index.js</code> and <code>app.js</code>, created by Amplify.</p>
  
  <p><code>index.js</code> is very short:</p>
  
  <pre><code>const awsServerlessExpress = require('aws-serverless-express');
  const app = require('./app');
  
  const server = awsServerlessExpress.createServer(app);
  
  exports.handler = (event, context) =&gt; {
    console.log(`EVENT: ${JSON.stringify(event)}`);
    awsServerlessExpress.proxy(server, event, context);
  };
  </code></pre>
  
  <p>And <code>app.js</code> consists in some set up (first screenshot) and then a series of methods for <code>get</code>, <code>put</code>, <code>post</code>, <code>delete</code>. I'm just including two screenshots for the <code>get</code> methods -- subject of this question).</p>
  
  <p><a href="https://i.stack.imgur.com/H9f1i.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/H9f1i.png" alt="enter image description here"></a></p>
  
  <p><a href="https://i.stack.imgur.com/8ZJXw.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/8ZJXw.png" alt="enter image description here"></a></p>
  
  <p><a href="https://i.stack.imgur.com/ILmiQ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ILmiQ.png" alt="enter image description here"></a></p>
  
  <p><strong>UPDATE 2</strong>
  Here's what I see when I click the Integration Request for the <code>ANY</code> method of my API. Note that I do not have a drop-down for the Mapping Template.</p>
  
  <p><a href="https://i.stack.imgur.com/3imjR.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/3imjR.png" alt="enter image description here"></a></p>
  
  <p><strong>UPDATE 3</strong>
  But I do have a <code>Prod</code> stage that Amplify created. But I still don't see a Mapping Template anywhere in sight.</p>
  
  <p><a href="https://i.stack.imgur.com/GCFGe.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/GCFGe.png" alt="enter image description here"></a></p>