【问题标题】:How to invoke my AWS API Gateway REST API in my iOS / Swift project如何在我的 iOS / Swift 项目中调用我的 AWS API Gateway REST API
【发布时间】:2019-07-04 05:06:04
【问题描述】:

我创建了一个单一视图应用程序in Xcode,然后按照 AWS Amplify iOS SDK 指南使用我现有的 Cognito 用户池插入身份验证。效果很好。

然后,使用 AWS Amplify,我added a REST API 允许我的 iOS 应用程序通过 Amplify 生成的 API 网关和 Lambda 函数访问预先存在的 DynamoDB 表。但是,我必须重新连接所有内容才能使用我预先存在的 Cognito 用户池,因为 Amplify CLI 意外创建了一个新的用户池,该用户池链接到它创建的 REST API。

我在尝试调用我的 API 时遇到以下错误,无论我做什么,我都无法让它消失:

Optional("{\"message\":\"Authorization header requires \'Credential\' parameter. 
Authorization header requires \'Signature\' parameter. Authorization header requires 
\'SignedHeaders\' parameter. 
Authorization=abJarWQiOiJyR0NiTHFsbVwvbWdGeXgzcVA1YmNRaV...
403

更新 5 更多血腥细节请看我的Amplify AWS iOS SDK issue。 :)

更新 4 此更新优先于我之前的更新,因为现在看起来很清楚——正如上面的错误所暗示的——我没有通过我的 iOS 应用程序的经过身份验证的 Cognito 用户正确调用我的 REST API。我注意到 Amplify 创建了一个用户池,其中包含 两个 应用程序客户端,一个用于 Web 访问,一个用于移动访问。我预先存在的用户池只有一个为 Web 访问量身定制的应用程序客户端。所以我为移动访问创建了一个新的应用客户端,带有一个应用客户端密码。

不幸的是,我得到了同样的错误。所以我想知道是否需要重新连接其他东西;或者我有一个令牌问题。正如我在下面的评论中提到的,也许我不应该使用 REST API 指南中指定的 OIDC 令牌?也许我应该使用AWS Credentials结束更新 4

我的 API 有一个资源 /items,我有一个 ANY 和一个 OPTIONS 方法。 ANY 方法没有为方法请求指定任何 URL 查询字符串参数。但它确实为请求正文指定了application/json 类型的RequestSchema

我的 API 调用函数正是 specified in the AWS Amplify iOS SDK for the REST API(我按照他们的说明使用 Cognito 用户池授权方调用我的 API 网关端点),除了我将 httpMethodNamePOST 更改为 GET 因为 POST 导致碰撞。这是它的样子:

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) -> 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
        }
    }

上面给出的错误是由那个print(responseString)打印出来的。

我的 DynamoDB 表需要:userId 的分区键。一个指导字符串。

我很确定我想要传递 API 的只是一个 userId,以便 API 可以检索与其关联的所有项目。不需要我的排序键。

我通过 API Gateway REST API 发出这个 GET 请求的方式有问题吗?

更新 1 有两个 JavaScript 文件与我的 Lambda 函数相关联:index.jsapp.js,由 Amplify 创建。

index.js 很短:

const awsServerlessExpress = require('aws-serverless-express');
const app = require('./app');

const server = awsServerlessExpress.createServer(app);

exports.handler = (event, context) => {
  console.log(`EVENT: ${JSON.stringify(event)}`);
  awsServerlessExpress.proxy(server, event, context);
};

app.js 包含一些设置(第一个屏幕截图),然后是getputpostdelete 的一系列方法。我只是为get 方法提供了两个屏幕截图——这个问题的主题)。

更新 2 这是我单击 API 的 ANY 方法的集成请求时看到的内容。请注意,我没有映射模板的下拉菜单。

更新 3 但我确实有一个 Amplify 创建的 Prod 阶段。但我仍然看不到任何映射模板。

【问题讨论】:

  • API 网关的映射模板,这里是如何查看它们的第 1 步:step 1 和第 2 步:step 2 image 并发布您看到的内容
  • 我很感激。你非常乐于助人……把我带到了我应该找的地方。我不知道为什么 AWS Amplify 没有为此 REST API 生成映射模板。我将对 API Gateway 进行更多研究,并将记住您的报价。谢谢!!
  • 您的映射模板将查询参数发送到您的 lambda 函数。如果没有这个,将不会传递任何参数,因此它会失败
  • 您在 headerParameters 中缺少 AWS 调用请求所需的一些参数。我曾经手动签署请求。 docs.aws.amazon.com/general/latest/gr/…
  • @motivus 你能用 Charles 调试器调试请求吗?我认为您可以在那里看到实际的请求并找出解决方案。

标签: ios swift amazon-web-services aws-api-gateway aws-amplify


【解决方案1】:

"/items/{userId}" 只是一个字符串。试试"/items/\(userId)"

抱歉,我没有足够的积分来发表评论。

【讨论】:

  • userId 在我的例子中是一个 Guid,它是一个字符串。所以上面将userId 视为整数文字。尽管如此,我感谢您的帮助!
  • 在 Swift 中,{userId} 不会被 userId 变量替换。您的 URLString 实际上是 /items/{userId}。我很确定这不是你的本意。要使用字符串插值,您需要使用\(userId)。那么你的 URLString 将是/items/whateverIsInTheUserIdVariable
  • 我明白你在说什么。那不是我的代码...我只是以这种方式代表这篇文章的指导。换句话说,那里有一个真正的向导。我更新了代码,所以这更清楚......
  • 好的,感谢您的澄清。您已经声明错误消息来自 print 语句,所以我只是假设它是您的代码。我希望你能解决这个问题。我记得我第一次使用 Cognito 和 API Gateway。这不是一次顺利的体验。
  • 谢谢唐。我的错。你肯定很有帮助,因为我不应该在我的代码 sn-p 中留下那个助记符。如果可以的话,我会支持你得到的反对票。
猜你喜欢
  • 2017-05-02
  • 1970-01-01
  • 2019-03-16
  • 2020-12-01
  • 2023-03-27
  • 1970-01-01
  • 2017-05-18
  • 2019-10-17
  • 2022-10-17
相关资源
最近更新 更多