Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to invoke an AWS Lambda function in Swift

I can't find any documentation or examples on how to invoke a Lambda function in Swift but I've tried to extrapolate from the documentation using Objective-C and I'm still getting errors:

"Error in myFunction: ValidationException: Supplied AttributeValue is empty, must contain exactly one of the supported datatypes"

It appears that I'm not passing in the parameters to the function correctly when I invoke the lambda function from swift because the script tries to write to DynamoDB but one of the parameters is empty (this lambda script works when I invoke it in javascript/node).

    let lambda = AWSLambda.defaultLambda()
    let request = AWSLambdaInvocationRequest()
    var context = [String: String]()
    let jsonString = "{\"email\":\"[email protected]\",\"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
    })
like image 286
JBaczuk Avatar asked Dec 03 '15 15:12

JBaczuk


People also ask

Does AWS Lambda support Swift?

Swift on AWSThe Swift AWS Lambda Runtime is designed to help Swift developers build serverless functions for AWS Lambda.

How are AWS Lambda function invoked?

You can invoke Lambda functions directly using the Lambda console, a function URL HTTP(S) endpoint, the Lambda API, an AWS SDK, the AWS Command Line Interface (AWS CLI), and AWS toolkits.

How do I manually trigger a Lambda function?

Invoke the Lambda function manually using sample Amazon S3 event data. On the Code tab, under Code source, choose the arrow next to Test, and then choose Configure test events from the dropdown list. In the Configure test event window, do the following: Choose Create new test event.


2 Answers

You need to set the payload parameter to a map containing the data you want to pass.

    let invocationRequest = AWSLambdaInvokerInvocationRequest()
    invocationRequest.functionName = "myFunction"
    invocationRequest.invocationType = AWSLambdaInvocationType.RequestResponse
    invocationRequest.payload = ["email" : "[email protected]", "name" : "example"]

    let lambdaInvoker = AWSLambdaInvoker.defaultLambdaInvoker()
    let task = lambdaInvoker.invoke(invocationRequest).continueWithSuccessBlock() { (task) -> AWSTask! in
        print("response: ", task.result)
    }
like image 133
Ryan Fitzgerald Avatar answered Oct 06 '22 12:10

Ryan Fitzgerald


Ryan Fitzgerald's answer gives me multiple compile-time errors, but I've had success with this version:

First, I have an initialization function with access credentials. Note that this is not the recommended secure access method for production code, but it is fine for testing and other purposes. It also assumes you have a Constants.swift file where you define the listed constants:

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
    }

For the remainder we can provide a version similar to the previous version. I removed the 'let task' because 'task' is not used in his example. Additionally, I've included the logical outline of some JSON parsing that you are likely to be doing inside the invoke task. Finally, I've changed to a continueWithBlock(). If you use a continueWithSuccessBlock() you will not enter this block when Amazon Lambda reaches its timeout window or if something else goes wrong with the request and typically you do want these situations to be handled here.

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

Tested and verified as functional on Swift 2.2 in Xcode 7.3.

like image 27
Ryan Davis Avatar answered Oct 06 '22 12:10

Ryan Davis