├── .dockerignore ├── .gitignore ├── .swift-version ├── .travis.yml ├── LICENSE ├── Package.swift ├── README.md ├── Shim └── index.js ├── Sources ├── AlexaSkill │ └── AlexaSkillHandler.swift ├── Lambda │ └── main.swift └── Server │ └── main.swift ├── Tests ├── AlexaSkillTests │ └── AlexaSkillHandlerTests.swift └── LinuxMain.swift ├── aws-sam-deploy.yml ├── aws-sam-package.yml ├── run-integration-tests.sh ├── run-unit-tests.sh ├── serverless.yml ├── session_start.json └── swift+lambda.png /.dockerignore: -------------------------------------------------------------------------------- 1 | .build 2 | Packages -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .serverless 3 | 4 | # Xcode 5 | # 6 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 7 | 8 | ## Build generated 9 | build/ 10 | DerivedData/ 11 | 12 | ## Various settings 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata/ 22 | 23 | ## Other 24 | *.moved-aside 25 | *.xcuserstate 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | Packages/ 41 | .build/ 42 | *.xcodeproj 43 | 44 | # CocoaPods 45 | # 46 | # We recommend against adding the Pods directory to your .gitignore. However 47 | # you should judge for yourself, the pros and cons are mentioned at: 48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 49 | # 50 | # Pods/ 51 | 52 | # Carthage 53 | # 54 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 55 | # Carthage/Checkouts 56 | 57 | Carthage/Build 58 | 59 | # fastlane 60 | # 61 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 62 | # screenshots whenever they are needed. 63 | # For more information about the recommended setup visit: 64 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 65 | 66 | fastlane/report.xml 67 | fastlane/Preview.html 68 | fastlane/screenshots 69 | fastlane/test_output 70 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 3.0.2 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | services: 4 | - docker 5 | 6 | # mkdir required here to avoid permission problem in script 7 | install: 8 | - mkdir -p .build/lambda/libraries 9 | - ./run-unit-tests.sh 10 | 11 | script: 12 | - ./run-integration-tests.sh -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Claus Höfele 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | import PackageDescription 2 | 3 | var package = Package( 4 | name: "AlexaSkill", 5 | targets: [ 6 | Target(name: "AlexaSkill"), 7 | Target(name: "Lambda", dependencies: ["AlexaSkill"]) 8 | ], 9 | dependencies: [ 10 | .Package(url: "https://github.com/choefele/AlexaSkillsKit", majorVersion: 0), 11 | ], 12 | exclude: ["Sources/Server"]) 13 | 14 | #if os(macOS) 15 | package.targets.append(Target(name: "Server", dependencies: ["AlexaSkill"])) 16 | package.dependencies.append(.Package(url: "https://github.com/IBM-Swift/Kitura", majorVersion: 1, minor: 1)) 17 | package.dependencies.append(.Package(url: "https://github.com/IBM-Swift/HeliumLogger", majorVersion: 1, minor: 1)) 18 | package.exclude = [] 19 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Swift + Amazon Lambda 3 |

4 | 5 | # Swift Lambda App 6 | Template to build an Amazon Lambda app in Swift 7 | 8 | [![Build Status](https://travis-ci.org/choefele/swift-lambda-app.svg?branch=master)](https://travis-ci.org/choefele/swift-lambda-app) 9 | 10 | ## Overview 11 | This repo contains code and scripts to quickly get you started with writing Swift apps for AWS Lambda, Amazon's serverless computing platform. It contains: 12 | - A sample Lambda app that implements a custom skill for Amazon's Alexa Voice Service using [AlexaSkillsKit](https://github.com/choefele/AlexaSkillsKit) 13 | - A setup to develop and test the app in your development environment 14 | - Scripts to build the app for the Lambda target environment 15 | - Integration tests to proof you app is working before deploying to Lambda 16 | - Instructions on deploying the app to Lambda (either manually or using Serverless) 17 | 18 | swift-lambda-app has been inspired by [SwiftOnLambda](https://github.com/algal/SwiftOnLambda), which provided the initial working code to execute Swift programs on Lambda. 19 | 20 | Also see the article [Serverless Swift](https://medium.com/@claushoefele/serverless-swift-2e8dce589b68#.97ijuj2x1) for a detailed introduction to running Swift on Lambda. 21 | 22 | ## Using this Repo as a Template 23 | Tools: [Serverless](https://serverless.com) (optional) 24 | 25 | Simply fork this repo to start developing your own Lambda function in Swift. Alternatively, you can use Serverless to make a copy of this repo for you by using `serverless install --url https://github.com/choefele/swift-lambda-app` 26 | 27 | ## Development 28 | Tools: [Xcode](https://developer.apple.com/download/), [ngrok](https://ngrok.com) (optional) 29 | 30 | The sample app in this repo uses a standard Swift Package Manager directory layout and [package file](https://github.com/choefele/swift-lambda-app/blob/master/Package.swift) thus `swift build`, `swift test` and `swift package generate-xcodeproj` work as expected. Check out the [SPM documentation](https://github.com/apple/swift-package-manager/blob/master/Documentation/Usage.md) for more info. 31 | 32 | There are three targets: 33 | - **AlexaSkill**: this is a library with the code that implements the custom Alexa skill. It's a separate library so it can be used by the other two targets. Also, libraries have `ENABLE_TESTABILITY` enabled by default which allows you to use `@testable import` in your unit tests. 34 | - **Lambda**: The command line executable for deployment to Lambda. This program uses `stdin` and `stdout` for processing data. 35 | - **Server** (macOS only): To simplify implementing a custom Alexa Skill, the Server target provides an HTTP interface to the AlexaSkill library. This HTTP server can be exposed publicly via ngrok and configured in the Alexa console, which enables you to develop and debug an Alexa skill with code running on your development server. This target is macOS only because it wasn't possible to cleanly separate target dependencies and I didn't want to link libraries intended for server development to the Lambda executable used for deployment. 36 | 37 | For development, I recommend a [TDD](https://en.wikipedia.org/wiki/Test-driven_development) approach against the library target because this results in the quickest turnaround for code changes. Uploading to Lambda to quickly verify changes isn't really an option because of slow updating times. Exposing your functionality via HTTPS as described below, however, enables you to test and debug your functionality in a slightly different way. 38 | 39 | To run a local HTTPS server: 40 | - Make sure the sample builds by running `swift build` 41 | - Generate an Xcode project with `swift package generate-xcodeproj` 42 | - Open the generated Xcode project, select the Server scheme and run the product (CMD-R). This will start a server at port 8090 43 | - Install ngrok via `brew cask install ngrok`. This tool allows you to expose a local HTTP server to the internet 44 | - Run `ngrok http 8090` and copy the HTTPS URL generated by ngrok (it looks similar to https://258ba658.ngrok.io) 45 | - To create an Alexa skill 46 | - Go to the [Alexa console](https://developer.amazon.com/edw/home.html#/skills/list) and create a new skill 47 | - Skill type: Custom Interaction Model 48 | - Intent: `{ "intents": [{"intent": "TestIntent"}]}` 49 | - Sample utterances: "TestIntent test swift" 50 | - SSL Certificate: Select "My development endpoint is a sub-domain of a domain that has a wildcard certificate from a certificate authority" 51 | - Service endpoint type: _HTTPS (use the URL from ngrok)_ 52 | 53 | Now you can test the skill in the Alexa Console using the utterance "test swift". This will call your local HTTP server allowing you to modify and debug your code with the Alexa service. 54 | 55 | ## Integration 56 | Tools: [Docker](https://www.docker.com/products/docker), [Travis](https://travis-ci.org/choefele/swift-lambda-app) 57 | 58 | Before uploading to Lambda, it's worthwhile to run the unit tests in a Linux environment and run integration tests that simulate the execution environment. This repo provides [`run-unit-tests.sh`](https://github.com/choefele/swift-lambda-app/blob/master/run-unit-tests.sh) to do the former and [`run-integration-tests.sh`](https://github.com/choefele/swift-lambda-app/blob/master/run-integration-tests.sh) to do the latter. 59 | 60 | `run-unit-tests.sh` builds and tests the Lambda target inside a Swift Docker container based on Ubuntu because there's currently no Swift compiler for Amazon Linux (based on RHEL). Executables built on different Linux distributions are compatible with each other if you provide all dependencies necessary to run the program. For this reason, the script captures all shared libraries required to run the executable using `ldd`. 61 | 62 | To prove that the resulting package works, `run-integration-tests.sh` runs a release build of the Swift code inside a Docker container that comes close to Lambda’s execution environment (unfortunately, [Amazon only provides a few Docker images](https://hub.docker.com/_/amazonlinux/) that don't necessarily match what [Lambda is using](http://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html)). 63 | 64 | The integration with Lambda is done via a small [Node.js script](https://github.com/choefele/swift-lambda-app/blob/master/Shim/index.js) that uses the `child_process` module to run the Swift executable. The script follows Amazon's recommendations to [run arbitrary executables in AWS Lambda](https://aws.amazon.com/blogs/compute/running-executables-in-aws-lambda/). 65 | 66 | After [configuring Travis](https://github.com/choefele/swift-lambda-app/blob/master/.travis.yml), you can run the same integration script also for every commit. 67 | 68 | ## Deploying the Lambda Function 69 | 70 | ### Deployment Using the Serverless Framework 71 | Tools: [Serverless](https://serverless.com) 72 | 73 | This project contains a `serverless.yml` configuration file for the [Serverless Framework](https://serverless.com), which automates uploading and configuring the Lambda function: 74 | 75 | - Make sure you have your [AWS credentials configured] for Serverless(https://serverless.com/framework/docs/providers/aws/guide/credentials/) 76 | - Run `run-integration-tests.sh` to produce a zip file at `.build/lambda/lambda.zip` with all required files to upload to Lambda 77 | - Run `sls deploy` to upload and configure the Lambda function 78 | 79 | To verify that the Lambda function works, run `sls invoke -f alexaSkill -p session_start.json` 80 | 81 | ### Manual Deployment 82 | To deploy your code to Lambda manually: 83 | 84 | - Run `run-integration-tests.sh` to produce a zip file at `.build/lambda/lambda.zip` with all required files to upload to Lambda 85 | - Create a new Lambda function in the [AWS Console](https://console.aws.amazon.com/lambda/home) in the US East/N. Virginia region (for Europe use EU/Ireland) 86 | - Use an Alexa Skills Kit trigger 87 | - Runtime: NodeJS 4.3 88 | - Code entry type: ZIP file (upload the `lambda.zip` file from the previous step) 89 | - Handler: index.handler 90 | - Role: Create from template or use existing role 91 | 92 | To verify that the Lambda function works, condigure a test event with the contents of `session_start.json` in the AWS console. 93 | 94 | ## Creating an Alexa Skill 95 | 96 | After creating the Lambda function, you can now create an Alexa skill: 97 | - Go to the [Alexa console](https://developer.amazon.com/edw/home.html#/skills/list) and create a new skill 98 | - Skill type: Custom Interaction Model 99 | - Intent: `{ "intents": [{"intent": "TestIntent"}]}` 100 | - Sample utterances: "TestIntent test swift" 101 | - Service endpoint type: AWS Lambda ARN (use the ARN from the AWS Console) 102 | 103 | Now you can test the skill in the Alexa Console using the utterance "test swift". More details on configuring Alexa skills can be found on [Amazon's developer portal](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/overviews/steps-to-build-a-custom-skill). 104 | -------------------------------------------------------------------------------- /Shim/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const spawnSync = require('child_process').spawnSync; 4 | 5 | exports.handler = (event, context, callback) => { 6 | // Invoke the executable via the provided ld-linux.so – this will 7 | // force the right GLIBC version and its dependencies 8 | const options = { input:JSON.stringify(event) }; 9 | const command = 'libraries/ld-linux-x86-64.so.2'; 10 | const childObject = spawnSync(command, ["--library-path", "libraries", "./Lambda"], options) 11 | 12 | if (childObject.error) { 13 | callback(childObject.error, null); 14 | } else { 15 | try { 16 | // The executable's raw stdout is the Lambda output 17 | var stdout = childObject.stdout.toString('utf8'); 18 | var stderr = childObject.stderr.toString('utf8'); 19 | var response = JSON.parse(stdout); 20 | callback(null, response); 21 | } catch(e) { 22 | e.message += ": " + stderr 23 | callback(e, null); 24 | } 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /Sources/AlexaSkill/AlexaSkillHandler.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import AlexaSkillsKit 3 | 4 | public class AlexaSkillHandler : RequestHandler { 5 | public init() { 6 | } 7 | 8 | public func handleLaunch(request: LaunchRequest, session: Session, next: @escaping (StandardResult) -> ()) { 9 | let standardResponse = generateResponse(message: "Alexa Skill received launch request") 10 | next(.success(standardResponse: standardResponse, sessionAttributes: session.attributes)) 11 | } 12 | 13 | public func handleIntent(request: IntentRequest, session: Session, next: @escaping (StandardResult) -> ()) { 14 | let standardResponse = generateResponse(message: "Alexa Skill received intent \(request.intent.name)") 15 | next(.success(standardResponse: standardResponse, sessionAttributes: session.attributes)) 16 | } 17 | 18 | public func handleSessionEnded(request: SessionEndedRequest, session: Session, next: @escaping (VoidResult) -> ()) { 19 | next(.success()) 20 | } 21 | 22 | func generateResponse(message: String) -> StandardResponse { 23 | let outputSpeech = OutputSpeech.plain(text: message) 24 | return StandardResponse(outputSpeech: outputSpeech) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Lambda/main.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import AlexaSkillsKit 3 | import AlexaSkill 4 | 5 | do { 6 | let data = FileHandle.standardInput.readDataToEndOfFile() 7 | let requestDispatcher = RequestDispatcher(requestHandler: AlexaSkillHandler()) 8 | let responseData = try requestDispatcher.dispatch(data: data) 9 | FileHandle.standardOutput.write(responseData) 10 | } catch let error as MessageError { 11 | let data = error.message.data(using: .utf8) ?? Data() 12 | FileHandle.standardOutput.write(data) 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Server/main.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import AlexaSkillsKit 3 | import AlexaSkill 4 | import Kitura 5 | import HeliumLogger 6 | 7 | HeliumLogger.use() 8 | 9 | let router = Router() 10 | router.get("/ping") { request, response, next in 11 | response.send("pong") 12 | next() 13 | } 14 | 15 | router.all("/") { request, response, next in 16 | var data = Data() 17 | let _ = try? request.read(into: &data) 18 | 19 | let requestDispatcher = RequestDispatcher(requestHandler: AlexaSkillHandler()) 20 | requestDispatcher.dispatch(data: data) { result in 21 | switch result { 22 | case .success(let data): 23 | response.send(data: data).status(.OK) 24 | case .failure(let error): 25 | response.send(error.message).status(.badRequest) 26 | } 27 | 28 | next() 29 | } 30 | } 31 | 32 | Kitura.addHTTPServer(onPort: 8090, with: router) 33 | Kitura.run() 34 | -------------------------------------------------------------------------------- /Tests/AlexaSkillTests/AlexaSkillHandlerTests.swift: -------------------------------------------------------------------------------- 1 | @testable import AlexaSkill 2 | import AlexaSkillsKit 3 | import Foundation 4 | import XCTest 5 | 6 | class AlexaSkillHandlerTests: XCTestCase { 7 | static let allTests = [ 8 | ("testHandleIntent", testHandleIntent) 9 | ] 10 | 11 | var alexaSkillHandler: AlexaSkillHandler! 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | alexaSkillHandler = AlexaSkillHandler() 17 | } 18 | 19 | func testHandleIntent() { 20 | let request = Request(requestId: "requestId", timestamp: Date(), locale: Locale(identifier: "en")) 21 | let intentRequest = IntentRequest(request: request, intent: Intent(name: "name")) 22 | let application = Application(applicationId: "applicationId") 23 | let user = User(userId: "userId") 24 | let session = Session(isNew: true, sessionId: "sessionId", application: application, attributes: [:], user: user) 25 | 26 | let testExpectation = expectation(description: #function) 27 | alexaSkillHandler.handleIntent(request: intentRequest, session: session) { result in 28 | switch result { 29 | case .success(let result): 30 | XCTAssertEqual(result.standardResponse.outputSpeech, OutputSpeech.plain(text: "Alexa Skill received intent name")) 31 | XCTAssertTrue(result.sessionAttributes.isEmpty) 32 | case .failure: 33 | XCTFail() 34 | } 35 | 36 | testExpectation.fulfill() 37 | } 38 | waitForExpectations(timeout: 1) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | #if os(Linux) 2 | import XCTest 3 | 4 | @testable import AlexaSkillTests 5 | 6 | XCTMain([ 7 | testCase(AlexaSkillHandlerTests.allTests) 8 | ]) 9 | #endif -------------------------------------------------------------------------------- /aws-sam-deploy.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: swift-lambda-app 3 | Resources: 4 | AlexaSkillFunction: 5 | Properties: 6 | CodeUri: s3://swift-lambda-app-us-east-1/fb9826eb5bc997a1ea9147b665d6097d 7 | Events: 8 | AlexaSkillEvent: 9 | Type: AlexaSkill 10 | Handler: index.handler 11 | Runtime: nodejs4.3 12 | Type: AWS::Serverless::Function 13 | Transform: AWS::Serverless-2016-10-31 14 | -------------------------------------------------------------------------------- /aws-sam-package.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: swift-lambda-app 4 | Resources: 5 | AlexaSkillFunction: 6 | Type: AWS::Serverless::Function 7 | Properties: 8 | Handler: index.handler 9 | Runtime: nodejs4.3 10 | CodeUri: .build/lambda/lambda.zip 11 | Events: 12 | AlexaSkillEvent: 13 | Type: AlexaSkill -------------------------------------------------------------------------------- /run-integration-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | SWIFT_VERSION=$(<.swift-version) 6 | 7 | # Build Swift executable 8 | docker run \ 9 | --rm \ 10 | --volume "$(pwd):/app" \ 11 | --workdir /app \ 12 | swift:$SWIFT_VERSION \ 13 | swift build -c release --build-path .build/native 14 | mkdir -p .build/lambda 15 | cp .build/native/release/Lambda .build/lambda/ 16 | 17 | # Copy libraries necessary to run Swift executable 18 | mkdir -p .build/lambda/libraries 19 | docker run \ 20 | --rm \ 21 | --volume "$(pwd):/app" \ 22 | --workdir /app \ 23 | swift:$SWIFT_VERSION \ 24 | /bin/bash -c "ldd .build/native/release/Lambda | grep so | sed -e '/^[^\t]/ d' -e 's/\t//' -e 's/.*=..//' -e 's/ (0.*)//' | xargs -i% cp % .build/lambda/libraries" 25 | 26 | # Run integration tests 27 | cp Shim/index.js .build/lambda/ 28 | docker run \ 29 | --rm \ 30 | --volume "$(pwd):/app" \ 31 | --workdir /app/.build/lambda \ 32 | --entrypoint node \ 33 | lambci/lambda \ 34 | -e 'var fs = require("fs");require("./").handler(JSON.parse(fs.readFileSync("../../session_start.json", "utf8")), {}, function(e, r) {if (e) {console.error(e);process.exit(1);} else {console.log(r);}});' 35 | 36 | # Zip Swift executable, libraries and Node.js shim 37 | cd .build/lambda 38 | rm -f lambda.zip 39 | zip -r lambda.zip * 40 | cd ../.. -------------------------------------------------------------------------------- /run-unit-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | SWIFT_VERSION=$(<.swift-version) 6 | 7 | # Run unit tests 8 | docker run \ 9 | --rm \ 10 | --volume "$(pwd):/app" \ 11 | --workdir /app \ 12 | swift:$SWIFT_VERSION \ 13 | swift test --build-path .build/native -------------------------------------------------------------------------------- /serverless.yml: -------------------------------------------------------------------------------- 1 | service: swift-lambda-app 2 | 3 | frameworkVersion: ">=1.4.0 <2.0.0" 4 | 5 | provider: 6 | name: aws 7 | runtime: nodejs4.3 8 | 9 | package: 10 | artifact: .build/lambda/lambda.zip 11 | 12 | functions: 13 | alexaSkill: 14 | handler: index.handler 15 | events: 16 | - alexaSkill -------------------------------------------------------------------------------- /session_start.json: -------------------------------------------------------------------------------- 1 | { 2 | "session": { 3 | "sessionId": "SessionId.17f7630a-031a-4870-b58f-18078b7a2df4", 4 | "application": { 5 | "applicationId": "amzn1.ask.skill.a9d951c5-b650-41d3-be01-e0f3795d4e0a" 6 | }, 7 | "attributes": {}, 8 | "user": { 9 | "userId": "amzn1.ask.account.AH5BIAF3T3DXHNCR2NKQFAENFHK4EU7PNRCE2AWFABL3XLOL3QH2HMTDGRYFSODNO22BFIB6BXTFVACPPWZHJCY3FCWNNV447HV37YYPIFYLZUN2L2HFGMATGGMY526IL5IJX55GVU7AQKFNEIX3EAZOFMXPF5P3LBY6NIYNTSC7VQBDPCHUVLKEOSI234FC3JG7EHY4NEVDIKY" 10 | }, 11 | "new": true 12 | }, 13 | "request": { 14 | "type": "IntentRequest", 15 | "requestId": "EdwRequestId.de35f909-5333-468a-ab26-744891669214", 16 | "locale": "en-US", 17 | "timestamp": "2016-10-29T19:30:46Z", 18 | "intent": { 19 | "name": "OneIntent", 20 | "slots": {} 21 | } 22 | }, 23 | "version": "1.0" 24 | } -------------------------------------------------------------------------------- /swift+lambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/choefele/swift-lambda-app/9c5f4febe753e586209eea7a82e5ed9cc4f5a255/swift+lambda.png --------------------------------------------------------------------------------