如何在Swift中调用AWS Lambda函数

8

我找不到任何关于如何在Swift中调用Lambda函数的文档或示例,但我已经尝试从Objective-C的文档中推断出来,但仍然遇到错误:

"myFunction中的错误:ValidationException:提供的AttributeValue为空,必须恰好包含支持的数据类型之一"

看起来当我从Swift中调用Lambda函数时,我没有正确地传递参数给函数,因为脚本尝试写入DynamoDB,但其中一个参数为空(当我在javascript/node中调用此Lambda脚本时,它可以正常工作)。

    let lambda = AWSLambda.defaultLambda()
    let request = AWSLambdaInvocationRequest()
    var context = [String: String]()
    let jsonString = "{\"email\":\"example@example.com\",\"name\":\"example\"}"
    let jsonData = jsonString.dataUsingEncoding(NSUTF8StringEncoding)
    request.clientContext = jsonData?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
    request.functionName = "myFunction"
    lambda.invoke(request).continueWithBlock( {
        (currentTask: AWSTask!) -> AWSTask in
        if (currentTask.error != nil) {
            // failed to execute.
            print("Error executing: ", currentTask.error)
            task.setError(currentTask.error)
        } else {
            print("token: ", currentTask.result)
            task.setResult(currentTask.result)
    }
        return currentTask
    })
3个回答

5
您需要将payload参数设置为包含要传递的数据的映射。
    let invocationRequest = AWSLambdaInvokerInvocationRequest()
    invocationRequest.functionName = "myFunction"
    invocationRequest.invocationType = AWSLambdaInvocationType.RequestResponse
    invocationRequest.payload = ["email" : "example@example.com", "name" : "example"]

    let lambdaInvoker = AWSLambdaInvoker.defaultLambdaInvoker()
    let task = lambdaInvoker.invoke(invocationRequest).continueWithSuccessBlock() { (task) -> AWSTask! in
        print("response: ", task.result)
    }

糟糕,那是我从使用Swift的lambda的一个应用程序中复制粘贴的错误。我现在已经从示例中删除了它。在应用程序中,我将lambda请求存储为ViewController上的属性,这使我可以在需要时取消当前请求。 - Ryan Fitzgerald
寻找 Android 上的相同问题,如果有人能帮忙! - Akash Dubey

3

瑞恩·菲茨杰拉德(Ryan Fitzgerald)的答案给了我多个编译时错误,但我使用了这个版本并成功了:

首先,我有一个带有访问凭据的初始化函数。请注意,这不是生产代码推荐的安全访问方法,但对于测试和其他目的而言是可以接受的。它还假定您有一个Constants.swift文件,在其中定义列出的常量:

func initializeLambda() {

        let credentialsProvider = AWSStaticCredentialsProvider.init(accessKey:Constants.AWS_ACCESS_KEY, secretKey: Constants.AWS_SECRET_KEY)
        let defaultServiceConfiguration = AWSServiceConfiguration(region: Constants.AWS_REGION, credentialsProvider: credentialsProvider)
        AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = defaultServiceConfiguration
    }

对于其余部分,我们可以提供类似以前版本的版本。 我删除了“let task”,因为在他的示例中未使用“task”。 此外,我已包括您可能在调用任务内进行的一些JSON解析的逻辑概述。 最后,我已更改为continueWithBlock()。 如果您使用continueWithSuccessBlock(),则当Amazon Lambda到达其超时窗口或请求出现其他问题时,您将不会进入此块,并且通常您确实希望在此处理这些情况。

    self.initializeLambda() //Call our previously written initialization function
    let invocationRequest = AWSLambdaInvokerInvocationRequest()
    invocationRequest.functionName = "functionName"
    invocationRequest.invocationType = AWSLambdaInvocationType.RequestResponse
    invocationRequest.payload = ["key1" : "value1", "key2" : "value2"]
    let lambdaInvoker = AWSLambdaInvoker.defaultLambdaInvoker()
    lambdaInvoker.invoke(invocationRequest).continueWithBlock() { (task: AWSTask) -> AWSTask in
         print("response: ", task.result)
         //In here you'll likely be parsing a JSON payload
         if let payload: AnyObject = task.result?.payload {
              if let error: AnyObject = payload.objectForKey("error") {
                   //If there is an error key in the JSON dictionary...
              } else {
                   //If the JSON dictionary has no error key...
              }
         return task; 
         }    
    }

在Xcode 7.3中,已经测试并验证了Swift 2.2的功能。


1
两位 Ryan 的回答都很好并且有用,我只想再添加一些想法。
在大多数情况下,在调用 Lambda 之前,您可能需要进行身份验证,因此您收到的错误可能不一定是由于 Lambda 调用而是由于身份验证失败。但是,在 AWS 中,有几种不同的身份验证方式,这将根据您拥有的凭据而变化。
Ryan Davis 向您展示了一种方式,其中您的后端团队已设置了 AWS 访问密钥和 AWS 密钥。
在我的情况下,我必须使用 AWS Cognito 身份池进行身份验证,还有用户池身份验证,因此您需要确定您的团队给您提供了哪些凭据,并阅读适当的身份验证文档。
由于我需要使用 AWS Cognito 身份池,因此我只有区域和身份池 ID,因此在 Swift 5 中,需要使用 AWS Cognito 身份池进行身份验证。
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: Constants.AWS_REGION,
                          identityPoolId: Constants.AWS_REGION.AWS_IDENTITY_POOL_ID)

let serviceConfiguration = AWSServiceConfiguration(region: Constants.AWS_REGION,
                           credentialsProvider: credentialsProvider)

AWSServiceManager.default().defaultServiceConfiguration = serviceConfiguration

然后Lambda调用基本保持不变,只是稍微更新了Swift 5语法:

if let invocationRequest = AWSLambdaInvokerInvocationRequest() {
      invocationRequest.functionName = "function_name"
      invocationRequest.invocationType = AWSLambdaInvocationType.requestResponse
      invocationRequest.payload = ["key_1": "value_1"]
      let lambdaInvoker = AWSLambdaInvoker.default()
      lambdaInvoker.invoke(invocationRequest) { (awsLambdaInvokerInvocationResponse, error) in
        
        guard let payload = awsLambdaInvokerInvocationResponse?.payload as? [String: String] else {
          
          // Handle error here
          return
        }
        
        if let userId = payload["message"] {
          print("USR Id: \(userId)")
        }
      }
    }

根据Lambda返回给您的有效负载结构,您需要调整处理方式,在我的情况下是:

{
  "message": "user-id-8868-8475-8757"
}

最后,记得导入所需的库以满足您的使用情况,对于我上面的情况,我需要:

import AWSCore
import AWSLambda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接