├── LICENSE ├── NOTICE.txt ├── README.md ├── README ├── README-CN.md ├── README-DE.md ├── README-ES.md ├── README-FR.md ├── README-IT.md ├── README-JP.md ├── README-KR.md ├── README-PT.md ├── README-RU.md └── README-TW.md ├── apigateway-mappingtemplate.txt ├── error.html ├── index.html ├── lambda-functions ├── aggregate-votes │ └── app.js └── receive-vote │ ├── README.MD │ ├── app.js │ └── package.json ├── lambda_webapp.template ├── mapping.txt ├── narrow.css ├── refresh.js └── vote.css /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | AWS Lambda Reference Architecture: Web Application 2 | lambda-refarch-webapp 3 | Copyright 2015 Amazon.com, Inc. or its affiliates. 4 | All Rights Reserved. 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Serverless Reference Architecture: Vote Application 2 | 3 | ## Note: The Vote Application serverless reference architecture was originally in the lambda-refarch-webapp repository and has since moved to this repository. 4 | 5 | README Languages: [DE](README/README-DE.md) | [ES](README/README-ES.md) | [FR](README/README-FR.md) | [IT](README/README-IT.md) | [JP](README/README-JP.md) | [KR](README/README-KR.md) | 6 | [PT](README/README-PT.md) | [RU](README/README-RU.md) | 7 | [CN](README/README-CN.md) | [TW](README/README-TW.md) 8 | 9 | Serverless Reference Architecture illustrating how to build dynamic web applications using [AWS Lambda](http://aws.amazon.com/lambda/) and Amazon API Gateway to authenticate and process API requests. 10 | 11 | By combining AWS Lambda with other AWS services, developers can build powerful web applications that automatically scale up and down and run in a highly available configuration across multiple data centers—with zero administrative effort required for scalability, backups, or multi–data center redundancy. 12 | 13 | This example looks at using AWS Lambda and Amazon API Gateway to build a dynamic voting application, which receives votes via SMS, aggregates the totals into Amazon DynamoDB, and uses Amazon Simple Storage Service (Amazon S3)to display the results in real time. 14 | 15 | The architecture described in this [diagram](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda-refarch-webapp.pdf) can be created with an AWS CloudFormation template. 16 | 17 | [The template](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) does the following: 18 | 19 | - Creates an S3 bucket named to hold your web app. 20 | - Creates a DynamoDB table named `VoteApp` to store votes 21 | - Creates a DynamoDB table named `VoteAppAggregates` to aggregate vote totals 22 | - Creates a Lambda function that allows your application to receive votes 23 | - Creates a Lambda function that allows your application to aggregate votes 24 | - Creates an AWS Identity and Access Management (IAM) role and policy to allow Lambda functions to write to Amazon CloudWatch Logs and write and query the DynamoDB tables 25 | 26 | ## Dynamic Dashboard 27 | 28 | The services and resources configured by the AWS CloudFormation template can be tested with the HTML page `index.html`, which relies on the HTML, JavaScript, and CSS files found in this repo. You can copy these files to the S3 bucket created by the AWS CloudFormation script. 29 | 30 | ## Instructions 31 | **Important:** The provided CloudFormation template retreives its Lambda code from a bucket in the us-east-1 region. To launch this sample in another region, please modify the template and upload the Lambda code to a bucket in that region. 32 | 33 | This example demonstrates receiving votes via text message from users via a phone number. To duplicate the system built by this architecture, you will need to set up a phone number with a third party, like [Twilio](http://twilio.com). For full details, read [our post](https://medium.com/aws-activate-startup-blog/building-dynamic-dashboards-using-aws-lambda-and-amazon-dynamodb-streams-part-ii-b2d883bebde5) on the [AWS Startup Collection at Medium](https://medium.com/aws-activate-startup-blog). 34 | 35 | Step 1 – Create an AWS CloudFormation stack with the [template](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) using a lowercase name for the stack. 36 | 37 | Step 2 – Visit the [API Gateway dashboard](https://console.aws.amazon.com/apigateway/home) in your AWS account and create a new resource with a `/vote` endpoint. Assign a POST method that has the `Integration Request` type of "Lambda Function," and point to the Lambda function created by the AWS CloudFormation script that receives votes from your third-party voting service (in this example, Twilio). 38 | 39 | Under `Body Mapping Templates`, set the "Content-Type" to `application/x-www-form-urlencoded`, and add [this mapping template](apigateway-mappingtemplate.txt). 40 | 41 | Step 3 – Visit the [Amazon Cognito dashboard](https://console.aws.amazon.com/cognito/home) and create a new identity pool that allows access to unauthenticated identities. Modify the policy document to allow `GetItem` and `Scan` access to the aggregates DynamoDB table created by the AWS CloudFormation script above. This allows unauthenticated users to retrieve data from the vote aggregation table in DynamoDB. Amazon Cognito will provide sample code for the JavaScript platform. Note the value for identity pool ID; you'll need it in step 5. 42 | 43 | Step 4 – In the __VoteApp__ table in DynamoDB, create a new [Trigger](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.Lambda.html), and point it to the existing Lambda function to [aggregate votes](lambda-functions/aggregate-votes/app.js). This function will monitor any changes to your __VoteApp__ table, writing new, aggregate values into __VoteAppAggregates__. 44 | 45 | Step 5 – Copy the HTML, CSS, and JS files from this repo and into the static S3 bucket that was created to hold your dashboard. You'll need to open `refresh.js` and replace default values of `region` and `identity-pool-id` with your own values. 46 | 47 | Congratulations! You now should have a working example of the reference architecture. You are able to receive votes in real time, tune your DynamoDB table to handle various levels of incoming traffic, and watch your results change on your dashboard in real time! 48 | 49 | ## Worth Noting 50 | 51 | The AWS CloudFormation script will create two DynamoDB tables for you. Although you are able to specify the read and write capacity through the AWS CloudFormation script, you are not able to specify the table names in the script. This is because the JavaScript code that receives and aggregates votes must know the names of that tables (_VoteApp_ and _VoteAppAggregates_) in advance. If you would like to change the names of your DynamoDB tables, make sure to change the names in the JavaScript files themselves in the code found in both [the aggregate source](/lambda-functions/aggregate-votes/) and [the receiving source](/lambda-functions/receive-vote/). 52 | 53 | ## Cleanup 54 | 55 | To remove all automatically created resources, delete the AWS CloudFormation stack. You will need to manually remove the API Gateway endpoint and the Amazon Cognito identity pool. 56 | 57 | Note: Deletion of the S3 bucket will fail unless all files in the bucket are removed before the stack is deleted. 58 | 59 | ## License 60 | 61 | This reference architecture sample is licensed under Apache 2.0. 62 | -------------------------------------------------------------------------------- /README/README-CN.md: -------------------------------------------------------------------------------- 1 | # 无服务器参考架构:Web 应用程序 2 | 3 | 无服务器参考架构阐述了如何使用 [AWS Lambda](http://aws.amazon.com/lambda/) 构建动态 Web 应用程序以及使用 Amazon API Gateway 对 API 请求进行身份验证和处理。 4 | 5 | 通过将 AWS Lambda 与其他 AWS 服务相结合,开发人员可以构建功能强大的 Web 应用程序,这些应用程序能够自动扩展和缩减,并且可在多个数据中心之间以高度可用的配置运行,无需执行任何管理工作即可实现可扩展性、备份或多数据中心冗余。 6 | 7 | 此示例探讨了使用 AWS Lambda 和 Amazon API Gateway 构建动态投票应用程序,该应用程序接收通过 SMS 进行的投票,将投票结果汇总到 Amazon DynamoDB 中,并使用 Amazon Simple Storage Service (Amazon S3) 来实时显示结果。 8 | 9 | 可以使用 AWS CloudFormation 模板创建在此 [示意图](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda-refarch-webapp.pdf) 中介绍的架构。 10 | 11 | 使用 [模板](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) 可执行以下操作: 12 | 13 | - 创建名为 <S3BucketName\> 的 S3 存储桶来存放您的 Web 应用程序。 14 | - 创建名为 `VoteApp` 的 DynamoDB 表来存储投票 15 | - 创建名为 `VoteAppAggregates` 的 DynamoDB 表来汇总投票结果 16 | - 创建使您的应用程序能够接收投票的 Lambda 函数 17 | - 创建使您的应用程序能够汇总投票的 Lambda 函数 18 | - 创建 AWS Identity and Access Management (IAM) 角色和策略,以允许 Lambda 函数写入 Amazon CloudWatch 日志以及写入和查询 DynamoDB 表 19 | 20 | ## 动态仪表板 21 | 22 | AWS CloudFormation 模板配置的服务和资源可以使用 HTML 页面 `index.html` 进行测试,该页面采用在此存储库中找到的 HTML、JavaScript 和 CSS 文件。您可以将这些文件复制到由 AWS CloudFormation 脚本创建的 S3 存储桶。 23 | 24 | ## 说明 25 | **重要提示:** 提供的 CloudFormation 模板会从 us-east-1 区域的存储桶中检索其 Lambda 代码。要在另一个区域中启动此示例,请修改模板并将 Lambda 代码上传到该区域的存储桶中。 26 | 27 | 此示例演示了通过手机号接收用户使用文本短信发送的投票。要复制使用此架构构建的系统,您需要通过第三方设置电话号码,例如 [Twilio](http://twilio.com)。有关完整详细信息,请阅读 [AWS Startup Collection at Medium](https://medium.com/aws-activate-startup-blog) 上的 [我们的帖子](https://medium.com/aws-activate-startup-blog/building-dynamic-dashboards-using-aws-lambda-and-amazon-dynamodb-streams-part-ii-b2d883bebde5) 。 28 | 29 | 步骤 1 – 使用 [模板](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) 创建 AWS CloudFormation,对堆栈使用小写名称。 30 | 31 | 步骤 2 – 访问您的 AWS 账户中的 [API Gateway 仪表板](https://console.aws.amazon.com/apigateway/home),使用 `/vote` 终端节点创建新资源。分配带有 `Integration Request` 类型的 "Lambda Function" 的 POST 方法,并指向使用 AWS CloudFormation 脚本创建的 Lambda 函数,该函数将接收来自第三方投票服务的(在此示例中为 Twilio)的投票。 32 | 33 | 在 `Mapping Templates` 下,将 "Content-Type" 设置为 `application/x-www-form-urlencoded`,并添加 [此映射模板](apigateway-mappingtemplate.txt)。 34 | 35 | 步骤 3 – 访问 [Amazon Cognito 仪表板](https://console.aws.amazon.com/cognito/home) 并创建新的身份池,该身份池允许未经身份验证的身份进行访问。修改策略文档,以允许对以上 AWS CloudFormation 脚本创建的汇总 DynamoDB 表的读取访问。这将允许未经身份验证的用户从 DynamoDB 中的投票结果汇总表检索数据。Amazon Cognito 将提供适用于 JavaScript 平台的示例代码。请记录身份池 ID 的值;在步骤 4 中您将需要使用该信息。 36 | 37 | 步骤 4 – 将 HTML、CSS 和 JS 文件从此存储库复制到静态 S3 存储桶,该存储桶是为了存放您的仪表板而创建的。您需要打开 `refresh.js`,并将 `region` 和 `identity-pool-id` 的默认值替换为您自己的值。 38 | 39 | 恭喜您!现在您已经有了一个可以使用的参考架构示例。您可以实时接收投票,调整您的 DynamoDB 表以处理不同级别的传入流量,并可以实时查看您仪表板上的结果变化! 40 | 41 | ## 敬请注意 42 | 43 | AWS CloudFormation 脚本将为您创建两个 DynamoDB 表。虽然您可以通过 AWS CloudFormation 脚本指定读取和写入容量,不过您无法在脚本中指定表名。这是因为接收和汇总投票的 JavaScript 代码必须预先知道表的名称(_VoteApp_ 和 _VoteAppAggregates_)。如果您希望更改 DynamoDB 表的名称,请确保在 JavaScript 文件本身的代码中更改名称,这些名称位于 [汇总源](/lambda-functions/aggregate-votes/) 和 [接收源](/lambda-functions/receive-vote/) 中。 44 | 45 | ## 清理 46 | 47 | 要删除所有自动创建的资源,请删除 AWS CloudFormation 堆栈。您需要手动删除 API Gateway 终端节点以及 Amazon Cognito 身份池。 48 | 49 | 注意:除非在删除堆栈之前清除了存储桶中的所有文件,否则将无法删除 S3 存储桶。 50 | 51 | ## 许可证 52 | 53 | 此示例参考架构已获得 Apache 2.0 许可。 54 | -------------------------------------------------------------------------------- /README/README-DE.md: -------------------------------------------------------------------------------- 1 | # Serverlose Referenzarchitektur: Webanwendungen 2 | 3 | Die serverlose Referenzarchitektur veranschaulicht, wie dynamische Webanwendungen zur Authentifizierung und Verarbeitung von API-Anforderungen mithilfe von [AWS Lambda](http://aws.amazon.com/lambda/) und Amazon API Gateway erstellt werden. 4 | 5 | Durch die Kombination von AWS Lamda mit anderen AWS-Services können Entwickler leistungsfähige Webanwendungen erstellen, die automatisch nach oben oder unten skalieren und in einer hochverfügbaren Konfiguration über mehrere Rechenzentren hinweg ausgeführt werden – ohne den geringsten administrativen Aufwand für die Skalierbarkeit, für Sicherungen oder die Redundanz mehrerer Rechenzentren. 6 | 7 | In diesem Beispiel werden AWS Lambda und Amazon API Gateway zur Erstellung einer dynamischen Abstimmungsanwendung gezeigt. Die Anwendung erhält Stimmen über SMS, aggregiert die Summen in Amazon DynamoDB und verwendet Amazon Simple Storage Service (Amazon S3), um die Ergebnisse in Echtzeit anzuzeigen. 8 | 9 | Die in diesem [Diagramm](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda-refarch-webapp.pdf) beschriebene Architektur kann mithilfe einer AWS CloudFormation-Vorlage erstellt werden. 10 | 11 | [Die Vorlage](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) führt folgende Aktionen aus: 12 | 13 | - Erstellen eines Amazon S3-Buckets mit dem Namen <S3BucketName\> für Ihre Web-App 14 | - Erstellen einer DynamoDB-Tabelle mit dem Namen "VoteApp", um die Stimmen zu speichern 15 | - Erstellen einer DynamoDB-Tabelle mit dem Namen "VoteAppAggregates", um die Stimmensummen zu aggregieren 16 | - Erstellen einer Lambda-Funktion, die es Ihrer Anwendung ermöglicht, Stimmen zu empfangen 17 | - Erstellen einer Lambda-Funktion, die es Ihrer Anwendung ermöglicht, Stimmen zu aggregieren 18 | - Erstellen einer AWS Identity and Access Management (IAM) IAM-Rolle und -Richtlinie, um zu gestatten, dass die Lambda-Funktionen in die Amazon CloudWatch-Protokolle schreiben sowie DynamoDB-Tabellen schreiben und abfragen 19 | 20 | ## Dynamisches Dashboard 21 | 22 | Die über die AWS CloudFormation-Vorlage konfigurierten Services und Ressourcen können mithilfe der HTML-Seite "index.html", die auf die in diesem Repository enthaltenen HTML-, JavaScript- und CSS-Dateien basiert, getestet werden. Sie können diese Dateien in den S3-Bucket kopieren, der vom AWS CloudFormation-Skript erstellt wurde. 23 | 24 | ## Anweisungen 25 | **Wichtig:** Die bereitgestellte CloudFormation-Vorlage ruft ihren Lambda-Code aus einem Bucket für die Region "us-east-1" ab. Um dieses Beispiel in einer anderen Region zu starten, ändern Sie die Vorlage und laden Sie den Lambda-Code in einen Bucket für diese Region hoch. 26 | 27 | Dieses Beispiel zeigt, wie Stimmen von Benutzern aus Textnachrichten über eine Telefonnummer empfangen werden. Um das von dieser Architektur erstellte System zu duplizieren, müssen Sie eine Telefonnummer bei einem Drittanbieter einrichten, beispielsweise [Twilio](http://twilio.com). Umfassende Informationen dazu erhalten Sie in [unserem Post](https://medium.com/aws-activate-startup-blog/building-dynamic-dashboards-using-aws-lambda-and-amazon-dynamodb-streams-part-ii-b2d883bebde5) auf dem Blog ["AWS Startup Collection" bei Medium](https://medium.com/aws-activate-startup-blog). 28 | 29 | Schritt 1 – Erstellen Sie mithilfe [der Vorlage](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) einen AWS CloudFormation-Stapel und verwenden Sie Kleinbuchstaben für den Stapelnamen. 30 | 31 | Schritt 2 – Rufen Sie in Ihrem AWS-Konto das [API Gateway-Dashboard](https://console.aws.amazon.com/apigateway/home) auf und erstellen Sie eine neue Ressource mit einem "/vote"-Endpunkt. Weisen Sie eine POST-Methode zu, die den Typ "Integration Request" der "Lambda Function" aufweist und verweisen Sie auf die vom AWS CloudFormation-Skript erstellte Lambda-Funktion, die die Stimmen von Ihrem Drittanbieter empfängt (in diesem Beispiel Twilio). 32 | 33 | Setzen Sie unter "Mapping Templates" den "Content-Type" auf "application/x-www-form-urlencoded" und fügen Sie [diese Zuordnungsvorlage](apigateway-mappingtemplate.txt) hinzu. 34 | 35 | Schritt 3 – Rufen Sie das [Amazon Cognito-Dashboard](https://console.aws.amazon.com/cognito/home) auf und erstellen Sie einen neuen Identitäts-Pool, der nicht authentifizierten Identitäten Zugriff gewährt. Ändern Sie das Richtliniendokument, damit Lesezugriff auf die DynamoDB-Tabelle mit den aggregierten Daten gewährt wird – dies ist die Tabelle, die vom oben genannten AWS CloudFormation-Skript erstellt wurde. Dadurch können nicht authentifizierte Benutzer Daten aus der Tabelle mit den aggregierten Stimmen in DynamoDB abrufen. Amazon Cognito liefert den Beispiel-Code für die JavaScript-Plattform. Notieren Sie die Identitäts-Pool-ID; Sie benötigen sie in Schritt 4. 36 | 37 | Schritt 4 – Kopieren Sie die HTML-, CSS- und JS-Dateien aus diesem Repository in den statischen S3-Bucket, der für Ihr Dashboard erstellt wurde. Sie müssen "refresh.js" öffnen und die Standardwerte für "region" und "identity-pool-id" durch Ihre eigenen Werte ersetzen. 38 | 39 | Herzlichen Glückwunsch! Sie sollten nun über ein funktionierendes Beispiel der Referenzarchitektur verfügen. Sie können Stimmen in Echtzeit empfangen, Ihre DynamoDB-Tabelle so abstimmen, dass unterschiedliches Datenverkehrsaufkommen bewältigt wird, und die Ergebnisse auf Ihrem Dashboard in Echtzeit verfolgen. 40 | 41 | ## Hinweise 42 | 43 | Das AWS CloudFormation-Skript erstellt zwei DynamoDB-Tabellen. Obwohl die Lese- und Schreibkapazität mit dem AWS CloudFormation-Skript festgelegt werden kann, können Sie die Tabellennamen nicht im Skript angeben. Der Grund hierfür ist, dass dem JavaScript-Code, der die Stimmen empfängt und aggregiert, die Namen dieser Tabellen ("_VoteApp_" und "_VoteAppAggregates_") vorab bekannt sein müssen. Wenn Sie die Namen Ihrer DynamoDB-Tabellen ändern möchten, achten Sie darauf, die Namen in den JavaScript-Dateien selbst zu ändern, und zwar im [Quellcode für die aggregierten Daten](/lambda-functions/aggregate-votes/) wie auch im [Quellcode für den Stimmenempfang](/lambda-functions/receive-vote/). 44 | 45 | ## Bereinigung 46 | 47 | Um alle automatisch erstellten Ressourcen zu entfernen, löschen Sie den AWS CloudFormation-Stapel. Sie müssen den API Gateway-Endpunkt und den Identitäts-Pool für Amazon Cognito manuell entfernen. 48 | 49 | Hinweis: Das Entfernen des S3-Buckets wird fehlschlagen, wenn nicht alle Dateien im Bucket entfernt werden, bevor der Stapel gelöscht wird. 50 | 51 | ## Lizensierung 52 | 53 | Dieses Beispiel einer Referenzarchitektur ist unter Apache 2.0 lizensiert. 54 | -------------------------------------------------------------------------------- /README/README-ES.md: -------------------------------------------------------------------------------- 1 | # Arquitectura de referencia sin servidor: Aplicaciones web 2 | 3 | La arquitectura de referencia sin servidor ilustra cómo crear aplicaciones web dinámicas mediante [AWS Lambda](http://aws.amazon.com/lambda/) y Amazon API Gateway para autenticar y procesar solicitudes de la API. 4 | 5 | Combinando AWS Lambda con otros servicios de AWS, los desarrolladores pueden crear aplicaciones web eficaces que se amplíen y reduzcan automáticamente, y ejecutar una configuración de alta disponibilidad en varios centros de datos sin tener que realizar ningún esfuerzo administrativo para proporcionar escalabilidad, backups o redundancia en varios centros de datos. 6 | 7 | En este ejemplo se examina cómo usar AWS Lambda y Amazon API Gateway para crear una aplicación dinámica de emisión de votos, que recibe los votos a través de SMS, suma los totales en Amazon DynamoDB y usa Amazon Simple Storage Service (Amazon S3) para mostrar los resultados en tiempo real. 8 | 9 | La arquitectura descrita en este [diagrama](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda-refarch-webapp.pdf) se puede crear con una plantilla de AWS CloudFormation. 10 | 11 | [La plantilla](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) hace lo siguiente: 12 | 13 | - Crea un bucket de S3 llamado <S3BucketName\> para almacenar la aplicación web. 14 | - Crea una tabla de DynamoDB llamada `VoteApp` para almacenar los votos 15 | - Crea una tabla de DynamoDB llamada `VoteAppAggregates` para sumar los totales de votos 16 | - Crea una función Lambda que permite a la aplicación recibir los votos 17 | - Crea una función Lambda que permite a la aplicación sumar los votos 18 | - Crea un rol y una política de AWS Identity and Access Management (IAM) para permitir que las funciones Lambda escriban en los logs de Amazon CloudWatch y escriban en las tablas de DynamoDB y las consulten 19 | 20 | ## Panel dinámico 21 | 22 | Los servicios y recursos configurados por la plantilla de AWS CloudFormation se pueden probar con la página HTML `index.html`, que usa archivos HTML, JavaScript y CSS de este repositorio. Puede copiar estos archivos en el bucket de S3 creado por el script de AWS CloudFormation. 23 | 24 | ## Instrucciones 25 | **Importante:** la plantilla de CloudFormation proporcionada recupera su código Lambda de un bucket de la región us-east-1. Para ejecutar este ejemplo en otra región, modifique la plantilla y cargue el código Lambda en un bucket de esa región. 26 | 27 | Este ejemplo muestra cómo recibir votos a través de mensajes de texto de los usuarios mediante un número de teléfono. Para duplicar el sistema creado por esta arquitectura, tendrá que configurar un número de teléfono con un proveedor externo, como [Twilio](http://twilio.com). Para obtener información detallada, consulte [nuestra entrada](https://medium.com/aws-activate-startup-blog/building-dynamic-dashboards-using-aws-lambda-and-amazon-dynamodb-streams-part-ii-b2d883bebde5) en [AWS Startup Collection at Medium](https://medium.com/aws-activate-startup-blog). 28 | 29 | Paso 1: Cree una pila de AWS CloudFormation con la [plantilla](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) usando un nombre en minúsculas para la pila. 30 | 31 | Paso 2: Visite el [panel de API Gateway](https://console.aws.amazon.com/apigateway/home) en su cuenta de AWS y cree un nuevo recurso con un punto de enlace `/vote`. Asigne un método POST que tenga el tipo `Integration Request` de "Lambda Function" y apunte a la función Lambda creada por el script de AWS CloudFormation que recibe el servicio de votos del proveedor externo (en este ejemplo, Twilio). 32 | 33 | En `Mapping Templates`, establezca "Content-Type" en `application/x-www-form-urlencoded` y añada [esta plantilla de mapeo](apigateway-mappingtemplate.txt). 34 | 35 | Paso 3: Visite el [panel de Amazon Cognito](https://console.aws.amazon.com/cognito/home) y cree un nuevo grupo de identidades para permitir el acceso a identidades no autenticadas. Modifique el documento de la política para permitir el acceso de lectura a la tabla de DynamoDB de totales agregados creada por el script de AWS CloudFormation anterior. Esto permitirá que los usuarios no autenticados reciban datos de la tabla de acumulación de votos de DynamoDB. Amazon Cognito proporcionará el código de muestra para la plataforma JavaScript. Anote el valor del identificador de grupo de identidades; lo necesitará en el paso 4. 36 | 37 | Paso 4: Copie los archivos HTML, CSS y JS de este repositorio en el bucket de S3 estático creado para almacenar el panel. Tendrá que abrir `refresh.js` y reemplazar los valores predeterminados de `region` e `identity-pool-id` por sus propios valores. 38 | 39 | ¡Enhorabuena! Ahora debería tener un ejemplo operativo de la arquitectura de referencia. Podrá recibir votos en tiempo real, ajustar la tabla de DynamoDB para atender varios niveles de tráfico entrante y ver cómo cambian los resultados en el panel en tiempo real. 40 | 41 | ## Observaciones 42 | 43 | El script de AWS CloudFormation creará dos tablas de DynamoDB automáticamente. Aunque puede especificar la capacidad de lectura y escritura a través del script de AWS CloudFormation, no puede especificar los nombres de las tablas en el script. Esto es así porque el código JavaScript que recibe y suma los votos debe conocer los nombres de esas tablas (_VoteApp_ y _VoteAppAggregates_) de antemano. Si desea cambiar los nombres de las tablas de DynamoDB, asegúrese de cambiar los nombres en los propios archivos JavaScript en el código del [origen de acumulación](/lambda-functions/aggregate-votes/) y [el origen de recepción](/lambda-functions/receive-vote/). 44 | 45 | ## Borrado 46 | 47 | Para eliminar automáticamente todos los recursos creados, borre la pila de AWS CloudFormation. Tendrá que eliminar manualmente el punto de enlace de API Gateway y el grupo de identidades de Amazon Cognito. 48 | 49 | Nota: el borrado del bucket de S3 dará un error a menos que se borren todos los archivos del bucket antes de eliminar la pila. 50 | 51 | ## Licencia 52 | 53 | Este ejemplo de arquitectura de referencia tiene licencia de Apache 2.0. 54 | -------------------------------------------------------------------------------- /README/README-FR.md: -------------------------------------------------------------------------------- 1 | # Architecture de référence sans serveur : Applications web 2 | 3 | Architecture de référence illustrant comment créer des applications web dynamiques à l'aide d'[AWS Lambda](http://aws.amazon.com/lambda/) et d'Amazon API Gateway pour authentifier et traiter des demandes d'API. 4 | 5 | En combinant AWS Lambda avec d'autres services AWS, les développeurs peuvent créer des applications web puissantes qui sont dimensionnées automatiquement et s'exécutent dans une configuration hautement disponible dans plusieurs data centers, sans aucun effort administratif requis pour l'évolutivité, les sauvegardes ou la redondance sur plusieurs data centers. 6 | 7 | Cet exemple illustre l'utilisation d'AWS Lambda et d'Amazon API Gateway pour créer une application de vote dynamique qui reçoit les votes via SMS, regroupe les totaux dans Amazon DynamoDB et utilise Amazon Simple Storage Service (Amazon S3) pour afficher les résultats en temps réel. 8 | 9 | L'architecture décrite dans ce [diagramme](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda-refarch-webapp.pdf) peut être créée avec un template AWS CloudFormation. 10 | 11 | [Le template](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) exécute les opérations suivantes : 12 | 13 | - Il crée un bucket (compartiment) S3 nommé <S3BucketName\> pour contenir votre application web. 14 | - Il crée une table DynamoDB appelée `VoteApp` pour stocker les votes 15 | - Il crée une table DynamoDB appelée `VoteAppAggregates` pour regrouper les totaux de votes 16 | - Il crée une fonction Lambda qui permet à votre application de recevoir les votes 17 | - Il crée une fonction Lambda qui permet à votre application de regrouper les votes 18 | - Il crée un rôle AWS Identity and Access Management (IAM) et une politique pour permettre aux fonctions Lambda d'écrire dans des journaux Amazon CloudWatch, et d'écrire dans les tables DynamoDB et les interroger 19 | 20 | ## Tableau de bord dynamique 21 | 22 | Les services et ressources configurés par le template AWS CloudFormation peuvent être testés avec la page HTML `index.html`, qui repose sur les fichiers HTML, JavaScript et CSS trouvés dans ce référentiel. Vous pouvez créer ces fichiers dans le bucket (compartiment) S3 créé par le script. AWS CloudFormation. 23 | 24 | ## Instructions 25 | **Important:** Le template CloudFormation fourni extrait son code Lambda d'un bucket dans la région us-east-1. Pour lancer cet exemple dans une autre région, veuillez modifier le template et charger le code Lambda dans un bucket de cette région. 26 | 27 | Cet exemple illustre la réception des votes par SMS envoyés par des utilisateurs via un numéro de téléphone. Pour dupliquer le système créé par cette architecture, vous devrez configurer un numéro de téléphone avec un service tiers, comme [Twilio](http://twilio.com). Pour plus de détails, lisez [notre billet](https://medium.com/aws-activate-startup-blog/building-dynamic-dashboards-using-aws-lambda-and-amazon-dynamodb-streams-part-ii-b2d883bebde5) sur le blog [AWS Startup Collection at Medium](https://medium.com/aws-activate-startup-blog). 28 | 29 | Étape 1 – Créez une stack AWS CloudFormation avec le [template](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) en utilisant un nom en minuscules pour la stack. 30 | 31 | Étape 2 – Accédez au [tableau de bord API Gateway](https://console.aws.amazon.com/apigateway/home) dans votre compte AWS et créez une ressource avec un Endpoint `/vote`. Attribuez une méthode POST ayant le type `Integration Request` (demande d'intégration) de « fonction Lambda » et pointez vers la fonction Lambda créée par le script AWS CloudFormation qui reçoit les votes de votre service de vote tiers (dans cet exemple, Twilio). 32 | 33 | Sous `Mapping Templates`, définissez "Content-Type" sur `application/x-www-form-urlencoded`, et ajoutez [ce template de mapping](apigateway-mappingtemplate.txt). 34 | 35 | Étape 3 – Accédez au [tableau de bord Amazon Cognito](https://console.aws.amazon.com/cognito/home) et créez un pool d'identités qui autorise l'accès à des identités non authentifiées. Modifiez le document de politique pour autoriser un accès en lecture à la table DynamoDB de regroupements créée par le script AWS CloudFormation ci-dessus. Cela permet aux utilisateurs non authentifiés d'extraire des données de la table de regroupement de votes dans DynamoDB. Amazon Cognito fournira un exemple de code pour la plateforme JavaScript. Notez la valeur de l'ID de pool d'identités ; vous en aurez besoin à l'étape 4. 36 | 37 | Étape 4 – Copiez les fichiers HTML, CSS et JS de ce référentiel vers le bucket (compartiment) S3 statique qui avait été créé pour contenir votre tableau de bord. Vous devrez ouvrir `refresh.js` et remplacer les valeurs par défaut de `region` et `identity-pool-id` par vos propres valeurs. 38 | 39 | Félicitations ! Vous devriez désormais disposer d'un exemple opérationnel d'architecture de référence. Vous pouvez recevoir les votes en temps réel, ajuster votre table DynamoDB pour traiter différents niveaux de trafic entrant et voir vos résultats changer sur votre tableau de bord en temps réel ! 40 | 41 | ## À noter 42 | 43 | Le script AWS CloudFormation va créer deux tables DynamoDB pour vous. Si vous pouvez spécifier la capacité de lecture et d'écriture par le biais du script AWS CloudFormation, vous n'êtes pas en mesure d'indiquer les noms de table dans le script. Cela est dû au fait que le code JavaScript qui reçoit et regroupe les votes doit connaître les noms de ces tables (_VoteApp_ et _VoteAppAggregates_) à l'avance. Si vous souhaitez changer les noms de vos tables DynamoDB, veillez à modifier les noms dans les fichiers JavaScript dans le code trouvé dans [la source de regroupement](/lambda-functions/aggregate-votes/) et [la source de réception](/lambda-functions/receive-vote/). 44 | 45 | ## Nettoyage 46 | 47 | Pour supprimer automatiquement toutes les ressources créées, supprimez la stack AWS CloudFormation. Vous devrez supprimer manuellement l'Endpoint API Gateway et le pool d'identités Amazon Cognito. 48 | 49 | Remarque : La suppression du bucket (compartiment) S3 échouera sauf si tous les fichiers du bucket ont été supprimés avant la suppression de la stack. 50 | 51 | ## Licence 52 | 53 | Cet exemple d'architecture de référence est fourni sous licence sous Apache 2.0. 54 | -------------------------------------------------------------------------------- /README/README-IT.md: -------------------------------------------------------------------------------- 1 | # Architettura di riferimento senza server: applicazioni Web 2 | 3 | Architettura di riferimento senza server che illustra come creare applicazioni Web dinamiche utilizzando [AWS Lambda](http://aws.amazon.com/lambda/) e Amazon API Gateway per autenticare ed elaborare le richieste di API. 4 | 5 | Grazie alla combinazione di AWS Lambda e altri servizi AWS, gli sviluppatori possono creare potenti applicazioni Web con scalabilità automatica ed eseguibili in una configurazione ad alta disponibilità su più data center, senza interventi amministrativi per scalabilità, backup o ridondanza in più data center. 6 | 7 | Questo esempio è incentrato sull'utilizzo di AWS Lambda e Amazon API Gateway per creare un'applicazione di voto dinamica, che riceve voti tramite SMS, aggrega i totali in Amazon DynamoDB e utilizza Amazon Simple Storage Service (Amazon S3) per la visualizzazione dei risultati in tempo reale. 8 | 9 | L'architettura descritta in questo [diagramma](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda-refarch-webapp.pdf) può essere creata con un modello di AWS CloudFormation. 10 | 11 | [Il modello](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) svolge le operazioni seguenti: 12 | 13 | - Creazione di un bucket S3 nominato <S3BucketName\> che contiene l'applicazione Web 14 | - Creazione di una tabella di DynamoDB nominata "VoteApp" in cui vengono archiviati i voti 15 | - Creazione di una tabella di DynamoDB nominata "VoteAppAggregates" in cui vengono aggregati i totali dei voti 16 | - Creazione di una funzione di Lambda che consente all'applicazione di ricevere i voti 17 | - Creazione di una funzione di Lambda che consente all'applicazione di aggregare i voti 18 | - Creazione di un ruolo e di una policy di AWS Identity and Access Management (IAM) che consentono alle funzioni di Lambda di scrivere nei registri di Amazon CloudWatch e di scrivere ed eseguire query nelle tabelle di DynamoDB 19 | 20 | ## Pannello di controllo dinamico 21 | 22 | I servizi e le risorse configurati dal modello di AWS CloudFormation possono essere testati con la pagina HTML "index.html", che utilizza i file HTML, JavaScript e CSS disponibili in questo repository. È possibile copiare questi file nel bucket S3 creato dallo script di AWS CloudFormation. 23 | 24 | ## Istruzioni 25 | **Important:** Il modello di CloudFormation fornito recupera il suo codice Lambda da un bucket nella regione Stati Uniti orientali 1. Per avviare questo esempio in un'altra regione, modificare il modello e caricare il codice Lambda in un bucket di quella regione. 26 | 27 | Questo esempio illustra la ricezione dei voti tramite messaggio di testo da utenti che utilizzano un numero telefonico. Per duplicare il sistema creato da questa architettura, è necessario impostare un numero telefonico con terze parti, come [Twilio](http://twilio.com). Per i dettagli completi, leggere [il nostro post](https://medium.com/aws-activate-startup-blog/building-dynamic-dashboards-using-aws-lambda-and-amazon-dynamodb-streams-part-ii-b2d883bebde5) su [AWS Startup Collection at Medium](https://medium.com/aws-activate-startup-blog). 28 | 29 | Passaggio 1: creare uno stack di AWS CloudFormation con il [modello](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) e assegnargli un nome con lettere minuscole. 30 | 31 | Passaggio 2: accedere al [pannello di controllo API Gateway](https://console.aws.amazon.com/apigateway/home) nell'account AWS personale e creare una nuova risorsa con un endpoint "/vote". Assegnare un metodo POST con "Lambda Function" di tipo "Integration Request" e indicare la funzione Lambda creata dallo script di AWS CloudFormation che riceve voti dal servizio di voto di terze parti (in questo esempio, Twilio). 32 | 33 | In "Mapping Templates", impostare "Content-Type" su "application/x-www-form-urlencoded" e aggiungere [questo modello di mapping] (apigateway-mappingtemplate.txt). 34 | 35 | Passaggio 3: accedere al [pannello di controllo Amazon Cognito](https://console.aws.amazon.com/cognito/home) e creare un nuovo pool di identità che consenta l'accesso a identità non autenticate. Modificare il documento della policy per consentire l'accesso per lettura alla tabella di aggregazione di DynamoDB creata dallo script di AWS CloudFormation. Ciò consente agli utenti non autenticati di recuperare i dati dalla tabella di aggregazione dei voti in DynamoDB. Amazon Cognito fornisce il codice di esempio per la piattaforma JavaScript. Prendere nota del valore per l'ID del pool di identità, necessario per il passaggio 4. 36 | 37 | Passaggio 4: copiare i file HTML, CSS e JS da questo repository nel bucket S3 statico creato per ospitare il pannello di controllo. Sarà necessario aprire "refresh.js" e sostituire i valori predefiniti di "region" e "identity-pool-id" con i valori a disposizione. 38 | 39 | Congratulazioni. L'esempio di architettura di riferimento è ora in funzione. È possibile ricevere voti in tempo reale, ottimizzare la tabella di DynamoDB per gestire vari livelli di traffico in entrata e visualizzare in tempo reale le variazioni dei risultati nel pannello di controllo. 40 | 41 | ## Nota 42 | 43 | Lo script di AWS CloudFormation crea due tabelle di DynamoDB. Sebbene sia possibile specificare la capacità di lettura e scrittura attraverso lo script di AWS CloudFormation, non è possibile specificare i nomi delle tabelle nello script. Questo perché il codice JavaScript che riceve e aggrega i voti deve conoscere in anticipo i nomi di tali tabelle (_VoteApp_ and _VoteAppAggregates_). Se si desidera modificare i nomi delle tabelle di DynamoDB, tali modifiche devono essere apportate nei file JavaScript stessi nel codice che si trova sia nella [fonte di aggregazione](/lambda-functions/aggregate-votes/) che nella [fonte di ricezione](/lambda-functions/receive-vote/). 44 | 45 | ## Eliminazione 46 | 47 | Per eliminare tutte le risorse create automaticamente, eliminare lo stack di AWS CloudFormation. È necessario eliminare manualmente l'endpoint di API Gateway e il pool di identità di Amazon Cognito. 48 | 49 | Nota: per eliminare il bucket S3, è necessario eliminare tutti i file nel bucket prima di eliminare lo stack. 50 | 51 | ## Licenza 52 | 53 | La licenza di questo esempio di architettura di riferimento è fornita con Apache 2.0. 54 | -------------------------------------------------------------------------------- /README/README-JP.md: -------------------------------------------------------------------------------- 1 | # サーバーレスリファレンスアーキテクチャ: ウェブアプリケーション 2 | 3 | [AWS Lambda](http://aws.amazon.com/lambda/) および Amazon API Gateway を使用して API リクエストを認証、処理する動的なウェブアプリケーションを構築する方法を示すサーバーレスリファレンスアーキテクチャ。 4 | 5 | 開発者は、AWS Lambda を他の AWS サービスと組み合わせることにより、自動的にスケールアップおよびスケールダウンし、複数のデータセンター間で可用性の高い設定で実行される強力なウェブアプリケーションを構築できます。スケーラビリティ、バックアップ、または複数のデータセンターの冗長性について運用管理の手間は一切かかりません。 6 | 7 | この例では、AWS Lambda と Amazon API Gateway を使用して動的な投票アプリケーションを構築する方法を示します。このアプリケーションは SMS 経由で投票を受け取り、合計を Amazon DynamoDB に集計し、Amazon Simple Storage Service (Amazon S3) を使用して結果をリアルタイムで表示します。 8 | 9 | この [図](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda-refarch-webapp.pdf) に示すアーキテクチャは、AWS CloudFormation テンプレートを使用して作成できます。 10 | 11 | [テンプレート](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) は以下を実行します。 12 | 13 | - ウェブアプリを保持するための <S3BucketName\> という S3 バケットを作成する 14 | - 投票を保存するための `VoteApp` という名前の DynamoDB テーブルを作成する 15 | - 投票の合計を集計するための `VoteAppAggregates` という名前の DynamoDB テーブルを作成する 16 | - アプリケーションが投票を受け取れるようにする Lambda 関数を作成する 17 | - アプリケーションが投票を集計できるようにする Lambda 関数を作成する 18 | - Lambda 関数が Amazon CloudWatch ログへの書き込み、および DynamoDB テーブルへの書き込みとクエリを実行できるようにする AWS Identity and Access Management (IAM) ロールとポリシーを作成する 19 | 20 | ## 動的ダッシュボード 21 | 22 | AWS CloudFormation テンプレートで設定されたサービスとリソースは、HTML ページ `index.html` でテストできます。このページは、このレポにある HTML、JavaScript、および CSS ファイルに依存します。AWS CloudFormation スクリプトによって作成された S3 バケットに、これらのファイルをコピーできます。 23 | 24 | ## 手順 25 | **重要:** 用意された CloudFormation テンプレートは、us-east-1 region リージョンのバケットからその Lambda コードを取得します。別のリージョンでこのサンプルを起動するには、テンプレートを変更し、そのリージョンのバケットに Lambda コードをアップロードします。 26 | 27 | この例では、電話番号でユーザーからテキストメッセージを通じて投票を受け取ります。このアーキテクチャによって構築されたシステムを複製するには、[Twilio](http://twilio.com) などのサードパーティーを使って電話番号を設定する必要があります。詳細については、[AWS Startup Collection at Medium](https://medium.com/aws-activate-startup-blog) の [投稿](https://medium.com/aws-activate-startup-blog/building-dynamic-dashboards-using-aws-lambda-and-amazon-dynamodb-streams-part-ii-b2d883bebde5) を参照してください。 28 | 29 | ステップ 1 – スタック用に小文字を使い、[テンプレート](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) で AWS CloudFormation スタックを作成します。 30 | 31 | ステップ 2 – AWS アカウントの [API Gateway ダッシュボード](https://console.aws.amazon.com/apigateway/home) にアクセスし、`/vote` エンドポイントで新しいリソースを作成します。`Integration Request` タイプの "Lambda 関数" を持つ POST メソッドを割り当て、サードパーティーの投票サービス (この例では Twilio) から投票を受け取る AWS CloudFormation スクリプトによって作成された Lambda 関数を指定します。 32 | 33 | `Mapping Templates` で、"Content-Type" を application/x-www-form-urlencoded` に設定し、[このマッピングテンプレート](apigateway-mappingtemplate.txt) を追加します。 34 | 35 | ステップ 3 - [Amazon Cognito ダッシュボード](https://console.aws.amazon.com/cognito/home) にアクセスし、認証されていない ID へのアクセスを許可する新しい ID プールを作成します。上記の AWS CloudFormation スクリプトによって作成された DynamoDB テーブルを集計するための読み取りアクセスを許可するポリシードキュメントを変更します。これにより、認証されていないユーザーが DynamoDB の投票集計テーブルからデータを受け取ることができます。Amazon Cognito が、JavaScript プラットフォーム用のサンプルコードを提供します。ID プール ID の値をメモしておきます。これはステップ 4 で必要になります。 36 | 37 | ステップ 4 – このレポから、ダッシュボードを保持するために作成された静的な S3 バケットに HTML、CSS、および JS ファイルをコピーします。`refresh.js` を開き、`region` および `identity-pool-id` のデフォルト値を独自の値に置き換える必要があります。 38 | 39 | おめでとうございます。これで、リファレンスアーキテクチャの例が完成しました。リアルタイムで投票を受け取り、DynamoDB テーブルを調整してさまざまなレベルの受信トラフィックを処理し、結果の変化をダッシュボードでリアルタイムに見ることができます。 40 | 41 | ## 注目すべき点 42 | 43 | AWS CloudFormation スクリプトでは、2 つの DynamoDB テーブルが作成されます。AWS CloudFormation スクリプトを通じて読み取りおよび書き込みキャパシティーを指定できますが、スクリプトでテーブル名を指定することはできません。これは、投票を受け取り集計する JavaScript コードが、そのテーブル名 (_VoteApp_ and _VoteAppAggregates_) を事前に知る必要があるためです。DynamoDB テーブルの名前を変更する場合は、必ず [集計ソース](/lambda-functions/aggregate-votes/) および [宛先ソース](/lambda-functions/receive-vote/) の両方にあるコードで JavaScript ファイル自体の名前を変更してください。 44 | 45 | ## クリーンアップ 46 | 47 | 自動的に作成されたすべてのリソースを削除するには、AWS CloudFormation スタックを削除します。API Gateway エンドポイントと Amazon Cognito ID プールを手動で削除する必要があります。 48 | 49 | 注意: スタックを削除する前にバケットのすべてのファイルを削除していないと、S3 バケットの削除は失敗します。 50 | 51 | ## ライセンス 52 | 53 | このリファレンスアーキテクチャサンプルは Apache 2.0 でライセンスされています。 54 | -------------------------------------------------------------------------------- /README/README-KR.md: -------------------------------------------------------------------------------- 1 | # 서버 없는 레퍼런스 아키텍처: 웹 애플리케이션 2 | 3 | API 요청을 인증 및 처리하기 위해 [AWS Lambda](http://aws.amazon.com/lambda/) 및 Amazon API Gateway를 사용하여 동적 웹 애플리케이션을 구축하는 방법을 보여주는 서버 없는 레퍼런스 아키텍처입니다. 4 | 5 | AWS Lambda와 다른 AWS 서비스를 결합하여 개발자는 확장, 백업 또는 다중 데이터 센터 중복성을 위해 필요한 관리 작업 없이 자동으로 확장/축소되고 여러 데이터 센터 간에 고가용성 구성을 실행할 수 있는 강력한 웹 애플리케이션을 구축할 수 있습니다. 6 | 7 | 이 예제에서는 AWS Lambda 및 Amazon API Gateway를 사용하여 SMS를 통해 투표를 진행하고, Amazon DynamoDB에 합계를 집계하고, Amazon Simple Storage Service(Amazon S3)를 사용하여 결과를 실시간으로 보여주는 동적 투표 애플리케이션을 구축하는 방법을 살펴봅니다. 8 | 9 | 이 [diagram](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda-refarch-webapp.pdf)에 설명된 아키텍처는 AWS CloudFormation 템플릿을 사용하여 만들 수 있습니다. 10 | 11 | [The template](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template)으로 다음을 수행할 수 있습니다. 12 | 13 | - 웹 앱을 저장할 이름이 <S3BucketName\>인 S3 버킷 생성 14 | - 투표를 저장할 이름이 `VoteApp`인 DynamoDB 테이블 생성 15 | - 투표 합계를 집계할 이름이 `VoteAppAggregates`인 DynamoDB 테이블 생성 16 | - 애플리케이션에서 투표를 진행할 수 있게 해주는 Lambda 함수 생성 17 | - 애플리케이션에서 투표를 집계할 수 있게 해주는 Lambda 함수 생성 18 | - Lambda 함수가 Amazon CloudWatch Logs에 쓰고 DynamoDB 테이블에 쓰고 쿼리할 수 있게 해주는 AWS Identity and Access Management(IAM) 역할 및 정책 생성 19 | 20 | ## 동적 대시보드 21 | 22 | AWS CloudFormation 템플릿을 통해 구성된 서비스와 리소스는 이 리포지토리에서 발견된 HTML, JavaScript 및 CSS 파일을 사용하는 HTML 페이지인 `index.html`을 사용하여 테스트할 수 있습니다. 이러한 파일을 AWS CloudFormation 스크립트로 만든 S3 버킷으로 복사할 수 있습니다. 23 | 24 | ## 지침 25 | **중요:** 제공된 CloudFormation 템플릿은 Lambda 코드를 us-east-1 리전의 버킷에서 가져옵니다. 이 샘플을 다른 리전에서 시작하려면 템플릿을 수정하고 Lambda 코드를 해당 리전의 버킷에 업로드하십시오. 26 | 27 | 이 예제는 전화 번호를 통해 사용자로부터 텍스트 메시지로 투표 결과를 수신하는 방법을 보여줍니다. 이 아키텍처로 만든 시스템을 복제하려면 [Twilio](http://twilio.com) 같은 타사의 전화 번호를 설정해야 합니다. 전체 세부 정보는 [AWS Startup Collection at Medium](https://medium.com/aws-activate-startup-blog)의 [게시물](https://medium.com/aws-activate-startup-blog/building-dynamic-dashboards-using-aws-lambda-and-amazon-dynamodb-streams-part-ii-b2d883bebde5) 에서 확인할 수 있습니다. 28 | 29 | 1단계 – 스택에 대해 소문자 이름을 지정하여 [template](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template)을 통해 AWS CloudFormation 스택을 만듭니다. 30 | 31 | 2단계 – AWS 계정에서 [API Gateway dashboard](https://console.aws.amazon.com/apigateway/home)로 이동하여 `/vote` 엔드포인트가 지정된 새 리소스를 만듭니다. `Integration Request` 유형이 "Lambda Function"인 POST 메서드를 할당하고 타사 투표 서비스(이 예제에서는 Twilio)로부터 투표 결과를 수신하는, AWS CloudFormation으로 만든 Lambda 함수를 가리키도록 합니다. 32 | 33 | `Mapping Templates`에서 "Content-Type"을 `application/x-www-form-urlencoded`로 설정하고 [this mapping template](apigateway-mappingtemplate.txt)을 추가합니다. 34 | 35 | 3단계 - [Amazon Cognito dashboard](https://console.aws.amazon.com/cognito/home)로 이동하여 인증되지 않은 자격 증명에 액세스할 수 있게 해주는 새 자격 증명 풀을 만듭니다. 위의 AWS CloudFormation 스크립트로 만든 집계 DynamoDB 테이블에 대한 읽기 액세스를 허용하도록 정책 문서를 수정합니다. 이렇게 하면 인증되지 않은 사용자가 DynamoDB의 투표 집계 테이블로부터 데이터를 가져갈 수 있습니다. Amazon Cognito는 JavaScript 플랫폼에 대한 샘플 코드를 제공합니다. 자격 증명 ID 값을 확인합니다. 이 값은 4단계에서 필요합니다. 36 | 37 | 4단계 – 이 리포지토리에서 HTML, CSS 및 JS 파일을 대시보드를 저장하기 위해 만든 정적 S3 버킷으로 복사합니다. `refresh.js`를 열고 `region` 및 `identity-pool-id`의 기본값을 적절한 값으로 변경해야 합니다. 38 | 39 | 축하합니다! 이제 사용 가능한 예제 레퍼런스 아키텍처를 만들었습니다. 실시간으로 투표를 진행하고 DynamoDB 테이블을 조정하여 다양한 수준의 수신 트래픽을 처리하고 대시보드에서 실시간으로 결과 변동 상황을 확인할 수 있습니다. 40 | 41 | ## 주의 사항 42 | 43 | AWS CloudFormation 스크립트는 두 DynamoDB 테이블을 만듭니다. AWS CloudFormation 스크립트를 통해 읽기 및 쓰기 용량을 지정할 수 있지만 이 스크립트에서 테이블 이름은 지정할 수 없습니다. 투표를 수신 및 집계하는 JavaScript 코드가 테이블의 이름((_VoteApp_ 및 _VoteAppAggregates_)을 사전에 알아야 하기 때문입니다. DynamoDB 테이블의 이름을 변경하려면 [he aggregate source](/lambda-functions/aggregate-votes/) 및 [the receiving source](/lambda-functions/receive-vote/)에서 찾을 수 있는 코드의 JavaScript 파일에서 이름을 변경합니다. 44 | 45 | ## 정리 46 | 47 | 자동으로 생성된 모든 리소스를 제거하려면 AWS CloudFormation 스택을 삭제합니다. API Gateway 엔드포인트 및 Amazon Cognito 자격 증명 풀은 직접 삭제해야 합니다. 48 | 49 | 참고: 스택을 삭제하기 전에 버킷에 있는 모든 파일을 제거하지 않으면 S3 버킷을 삭제할 수 없습니다. 50 | 51 | ## 라이선스 52 | 53 | 이 레퍼런스 아키텍처 샘플은 Apache 2.0에서 라이선스가 부여되었습니다. 54 | -------------------------------------------------------------------------------- /README/README-PT.md: -------------------------------------------------------------------------------- 1 | # Arquitetura de referência sem servidor: aplicações web 2 | 3 | Arquitetura de referência sem servidor ilustrando como criar aplicações web dinâmicas usando [AWS Lambda](http://aws.amazon.com/lambda/) e Amazon API Gateway para autenticar e processar solicitações da API. 4 | 5 | Combinando o AWS Lambda com outros serviços da AWS, os desenvolvedores podem criar aplicações avançadas que são dimensionadas automaticamente em uma configuração altamente disponível em vários datacenters, sem esforços administrativos necessários para escalabilidade, backups ou redundância de vários datacenters. 6 | 7 | Este exemplo analisa o uso de AWS Lambda e Amazon API Gateway para criar uma aplicação dinâmica de votação, que recebe votos via SMS, agrega os totais no Amazon DynamoDB e usa o Amazon Simple Storage Service (Amazon S3) para exibir os resultados em tempo real. 8 | 9 | A arquitetura descrita neste [diagrama](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda-refarch-webapp.pdf) pode ser criada com um modelo do AWS CloudFormation. 10 | 11 | [O modelo](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) faz o seguinte: 12 | 13 | - Cria um bucket S3 chamado <S3BucketName\> para conter sua aplicação web. 14 | - Cria uma tabela do DynamoDB chamada "VoteApp" para armazenar votos 15 | - Cria uma tabela do DynamoDB chamada "VoteAppAggregates" para agregar os totais de votos 16 | - Cria uma função de Lambda que permite que o aplicativo receba votos 17 | - Cria uma função de Lambda que permite que o aplicativo agregue votos 18 | - Cria uma função do AWS Identity and Access Management (IAM) e uma política para permitir que as funções do Lambda sejam gravadas nos registros do Amazon CloudWatch Logs e sejam gravadas e consultem as tabelas do DynamoDB 19 | 20 | ## Painel dinâmico 21 | 22 | Os serviços e recursos configurados pelo modelo do AWS CloudFormation podem ser testados com a página HTML "index.html", que depende dos arquivos HTML, JavaScript e CSS encontrados nesse repositório. Você pode copiar esses arquivos no bucket S3 criado pelo script do AWS CloudFormation. 23 | 24 | ## Instruções 25 | **Importante:** o modelo do CloudFormation fornecido recupera seu código do Lambda de um bucket na região us-east-1. Para iniciar esta amostra em outra região, modifique o modelo e faça o upload do código do Lambda em um bucket nessa região. 26 | 27 | Este exemplo demonstra o recebimento de votos via mensagem de texto enviada pelos usuários por um número de telefone. Para duplicar o sistema criado por essa arquitetura, você precisará configurar um número de telefone com terceiros, como [Twilio](http://twilio.com). Para obter todos os detalhes, leia [nossa postagem](https://medium.com/aws-activate-startup-blog/building-dynamic-dashboards-using-aws-lambda-and-amazon-dynamodb-streams-part-ii-b2d883bebde5) em [AWS Startup Collection at Medium](https://medium.com/aws-activate-startup-blog). 28 | 29 | Etapa 1 – Crie uma pilha do AWS CloudFormation com o [modelo](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) usando um nome em letras minúsculas para a pilha. 30 | 31 | Etapa 2 – Visite o [API Gateway dashboard](https://console.aws.amazon.com/apigateway/home) na sua conta da AWS e crie um novo recurso com um endpoint "/vote". Atribua um método POST que tenha o tipo "Solicitação de integração" da função do Lambda, e aponte para a função do Lambda criada pelo script do AWS CloudFormation que recebe votos do seu serviço de votação de terceiros (neste exemplo, Twilio). 32 | 33 | Em "Modelos de mapeamento", defina "Content-Type" como "application/x-www-form-urlencoded" e adicione [este modelo de mapeamento](apigateway-mappingtemplate.txt). 34 | 35 | Etapa 3 – Visite o [Amazon Cognito dashboard](https://console.aws.amazon.com/cognito/home) e crie um novo pool de identidade que permita o acesso a identidades não autenticadas. Modifique o documento de política para permitir o acesso de leitura à tabela agregada do DynamoDB criada pelo script do AWS CloudFormation acima. Desse modo, usuários não autenticados podem recuperar dados da tabela de agregação de votos no DynamoDB. O Amazon Cognito fornecerá o código de exemplo para a plataforma JavaScript. Anote o valor do ID do pool de identidade. Ele será necessário na etapa 4. 36 | 37 | Etapa 4 – Copie os arquivos HTML, CSS e JS desse repositório e no bucket S3 estático que foi criado para conter seu painel. Você precisará abrir "refresh.js" e substituir os valores padrão de "region" e "identity-pool-id" por seus próprios valores. 38 | 39 | Parabéns! Agora você deve ter um exemplo operacional da arquitetura de referência. Você pode receber votos em tempo real, ajustar sua tabela do DynamoDB para manipular vários níveis de tráfego de entrada e ver os resultados mudando no painel em tempo real. 40 | 41 | ## Observação 42 | 43 | O script do AWS CloudFormation criará duas tabelas do DynamoDB. Embora você consiga especificar a capacidade de leitura e gravação por meio do script do AWS CloudFormation, não conseguirá especificar os nomes de tabela no script. Isso acontece porque o código JavaScript que recebe e agrega votos deve saber os nomes dessas tabelas (_VoteApp_ e _VoteAppAggregates_) com antecedência. Se você quiser mudar os nomes das suas tabelas do DynamoDB, altere os nomes nos arquivos JavaScript propriamente ditos no código encontrado em [origem agregada](/lambda-functions/aggregate-votes/) e [origem de destino](/lambda-functions/receive-vote/). 44 | 45 | ## Limpeza 46 | 47 | Para remover todos os recursos criados automaticamente, exclua a pilha do AWS CloudFormation. Você precisará remover manualmente o endpoint do API Gateway e o pool de identidade do Amazon Cognito. 48 | 49 | Observação: a exclusão do bucket S3 falhará, a não ser que todos os arquivos do bucket sejam removidos antes da exclusão da pilha. 50 | 51 | ## Licença 52 | 53 | Este exemplo de arquitetura de referência é licenciado sob a licença do Apache 2.0. 54 | -------------------------------------------------------------------------------- /README/README-RU.md: -------------------------------------------------------------------------------- 1 | # Эталонная бессерверная архитектура: интернет-приложения 2 | 3 | Эта эталонная бессерверная архитектура позволяет понять, как создавать динамические интернет-приложения, используя [AWS Lambda](http://aws.amazon.com/lambda/) и Amazon API Gateway для аутентификации и обработки запросов API. 4 | 5 | Объединив AWS Lambda с другими сервисами AWS, разработчики могут создавать эффективные интернет-приложения, которые автоматически масштабируются и выполняются с высоким уровнем доступности в нескольких центрах обработки данных. При этом не нужно тратить время на реализацию масштабирования, резервного копирования и избыточности. 6 | 7 | В этом примере с помощью сервисов AWS Lambda и Amazon API Gateway создается динамическое приложение для голосования, которое получает голоса по SMS, передает данные в Amazon DynamoDB и отображает результаты в реальном времени с помощью Amazon Simple Storage Service (Amazon S3). 8 | 9 | Архитектуру, описанную на этой [схеме](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda-refarch-webapp.pdf), можно создать с помощью шаблона AWS CloudFormation. 10 | 11 | [Шаблон](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) выполняет следующие действия: 12 | 13 | - создает корзину S3 с именем <S3BucketName\> для размещения интернет-приложения; 14 | - создает таблицу DynamoDB с именем VoteApp для хранения голосов; 15 | - создает таблицу DynamoDB с именем VoteAppAggregates для хранения итогов голосования; 16 | - создает функцию Lambda, позволяющую приложению получать голоса; 17 | - создает функцию Lambda, позволяющую приложению обрабатывать голоса; 18 | - создает роль и политику AWS Identity and Access Management (IAM), которые позволяют функциям Lambda записывать данные в журналы Amazon CloudWatch и извлекать данные из таблиц DynamoDB. 19 | 20 | ## Динамическая панель управления 21 | 22 | Сервисы и ресурсы, настроенные шаблоном AWS CloudFormation, можно протестировать на HTML-странице index.html, которая использует файлы HTML, JavaScript и CSS, размещенные в этом репозитории. Вы можете скопировать их в корзину S3, созданную скриптом AWS CloudFormation. 23 | 24 | ## Инструкции 25 | **Важно!** Предоставленный шаблон CloudFormation извлекает код Lambda из корзины в регионе us-east-1. Чтобы запустить пример в другом регионе, измените шаблон и загрузите код Lambda в корзину в этом регионе. 26 | 27 | В этом примере показано, как получать голоса от пользователей по SMS по номеру телефона. Для копирования системы на основе этой архитектуры необходимо зарегистрировать номер телефона у стороннего поставщика, например [Twilio](http://twilio.com). Подробные сведения см. в [нашей публикации](https://medium.com/aws-activate-startup-blog/building-dynamic-dashboards-using-aws-lambda-and-amazon-dynamodb-streams-part-ii-b2d883bebde5) в [AWS Startup Collection at Medium](https://medium.com/aws-activate-startup-blog). 28 | 29 | Шаг 1. Создайте стек AWS CloudFormation с помощью [шаблона](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template), указав имя стека строчными буквами. 30 | 31 | Шаг 2. Откройте [панель управления API Gateway](https://console.aws.amazon.com/apigateway/home) в вашем аккаунте AWS и создайте ресурс с адресом «/vote». Назначьте метод POST с функцией Lambda Function типа «Integration Request» и укажите функцию Lambda, созданную скриптом AWS CloudFormation, которая получает голоса от стороннего сервиса (в этом пример – Twilio). 32 | 33 | В разделе «Mapping Templates» задайте для параметра «Content-Type» значение «application/x-www-form-urlencoded» и добавьте [этот шаблон соответствия](apigateway-mappingtemplate.txt). 34 | 35 | Шаг 3. Откройте [панель управления Amazon Cognito](https://console.aws.amazon.com/cognito/home) и создайте пул удостоверений, предоставляющий доступ к не прошедшим аутентификацию удостоверениям. Измените документ политики, чтобы разрешить доступ для чтения к таблице DynamoDB, созданной скриптом AWS CloudFormation, описанным выше. Это позволит не прошедшим аутентификацию пользователям извлекать данные из таблицы итогов голосования в DynamoDB. В Amazon Cognito представлен пример кода для платформы JavaScript. Запомните ID пула удостоверений, он потребуется на шаге 4. 36 | 37 | Шаг 4. Скопируйте файлы HTML, CSS и JS из этого репозитория в статическую корзину S3, созданную для хранения вашей панели управления. Вам потребуется открыть файл refresh.js и заменить значения параметров «region» и «identity-pool-id» по умолчанию на собственные значения. 38 | 39 | Поздравляем! Вы получили работающий пример эталонной архитектуры. Вы сможете получать голоса, настраивать таблицу DynamoDB для обработки различного объема входящего трафика и отслеживать результаты на панели управления в реальном времени. 40 | 41 | ## Примечания 42 | 43 | Скрипт AWS CloudFormation создает две таблицы DynamoDB. Хотя вы можете указать настройки чтения и записи в скрипте AWS CloudFormation, вы не сможете задать имена таблиц в нем. Это связано с тем, что в коде JavaScript, получающем и обрабатывающем голоса, заранее необходимо указать имена этих таблиц (_VoteApp_ и _VoteAppAggregates_). Если вы хотите изменить имена таблиц DynamoDB, поменяйте их в файлах JavaScript в [коде обработки](/lambda-functions/aggregate-votes/) и [коде получения](/lambda-functions/receive-vote/). 44 | 45 | ## Очистка 46 | 47 | Чтобы удалить все автоматически созданные ресурсы, удалите стек AWS CloudFormation. Вам потребуется вручную удалить адрес API Gateway и пул удостоверений Amazon Cognito. 48 | 49 | Примечание. Перед удалением корзины S3 необходимо удалить все файлы в ней. 50 | 51 | ## Лицензия 52 | 53 | Данная эталонная архитектура лицензирована в соответствии с лицензией Apache 2.0. 54 | -------------------------------------------------------------------------------- /README/README-TW.md: -------------------------------------------------------------------------------- 1 | # 無伺服器參考架構:Web 應用程式 2 | 3 | 無伺服器參考架構描述如何使用 [AWS Lambda](http://aws.amazon.com/lambda/) 與 Amazon API Gateway 建立動態 Web 應用程式以驗證與處理 API 要求。 4 | 5 | 藉由結合 AWS Lambda 與其他 AWS 服務,開發人員可建立強大的 Web 應用程式,以自動擴展與縮減並在跨多個資料中心的高可用性組態中運作,而且無需任何管理作業來處理可擴展性、備份或多重資料中心備援等作業。 6 | 7 | 此範例著眼於使用 AWS Lambda 與 Amazon API Gateway 建立動態投票應用程式,它可透過簡訊接受投票並將總數彙整至 Amazon DynamoDB,然後利用 Amazon Simple Storage Service (Amazon S3) 即時顯示結果。 8 | 9 | 使用 AWS CloudFormation 範本可建立此 [示意圖](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda-refarch-webapp.pdf) 所描述的架構。 10 | 11 | [範本](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) 執行以下項目: 12 | 13 | - 建立名為 <S3BucketName\> 的 S3 儲存貯體以存放您的 Web 應用程式。 14 | - 建立名為「VoteApp」的 DynamoDB 資料表以存放投票 15 | - 建立名為「VoteAppAggregates」的 DynamoDB 資料表以彙整投票總數 16 | - 建立 Lambda 功能讓您的應用程式接受投票 17 | - 建立 Lambda 功能讓您的應用程式彙整投票 18 | - 家裡 AWS Identity and Access Management (IAM) 角色與政策,讓 Lambda 功能寫入至 Amazon CloudWatch 記錄以及寫入與查詢 DynamoDB 資料表 19 | 20 | ## 動態儀表板 21 | 22 | 利用此儲存庫中的 HTML、JavaScript 及 CSS 建立的 HTML 網頁「index.html」,可測試 AWS CloudFormation 範本所設定的服務與資源。您可以將這些檔案複製至 AWS CloudFormation 指令碼所建立的 S3 儲存貯體中。 23 | 24 | ## 說明 25 | **重要:** 系統提供的 CloudFormation 範本會從 us-east-1 區域的儲存貯體取回其 Lambda 程式碼。若要在其他區域啟動此範例,請修改範本並將 Lambda 程式碼上傳至該區域的儲存貯體。 26 | 27 | 此範例示範透過使用者以電話號碼傳送的文字訊息以接受投票。若要複製此架構所建立的系統,您必須透過第三方設定電話號碼,例如 [Twilio](http://twilio.com)。如需完整的詳細資訊,請參閱 [AWS Startup Collection at Medium](https://medium.com/aws-activate-startup-blog) 上的 [我們的文章](https://medium.com/aws-activate-startup-blog/building-dynamic-dashboards-using-aws-lambda-and-amazon-dynamodb-streams-part-ii-b2d883bebde5) 。 28 | 29 | 步驟 1 – 使用 [範本](https://s3.amazonaws.com/awslambda-reference-architectures/web-app/lambda_webapp.template) 建立 AWS CloudFormation 堆疊,堆疊的名稱請使用小寫字母。 30 | 31 | 步驟 2 – 造訪您的 AWS 帳戶中的 [API Gateway 儀表板](https://console.aws.amazon.com/apigateway/home) 並以「/vote」終端節點建立新的資源。指派具有「整合要求」類型「Lambda 功能」的 POST 方法,然後指向由接受來自第三方投票服務 (例如 Twilio) 的投票的 AWS CloudFormation 指令碼建立的 Lambda 功能。 32 | 33 | 在「對應範本」之下,將「Content-Type」設定為「application/x-www-form-urlencoded」,然後新增 [此對應範本](apigateway-mappingtemplate.txt)。 34 | 35 | 步驟 3 – 造訪 [Amazon Cognito 儀表板](https://console.aws.amazon.com/cognito/home) 並建立新的允許存取未授權的身分的 Identity Pool。修改政策文件以允許讀取存取上述 AWS CloudFormation 指令碼建立的彙整 DynamoDB 資料表。如此可允許未經驗證的使用者從 DynamoDB 中的投票彙整資料表取回資料。Amazon Cognito 將提供此 JavaScript 平台的範本程式碼。請記下 Identity Pool ID 數值,您將會在步驟 4 使用此數值。 36 | 37 | 步驟 4 – 將此儲存庫的 HTML、CSS 及 JS 檔案複製至建立用來存放您的儀表板的靜態 S3 儲存貯體。您將必須開啟「refresh.js」並以您自己的數值取代「region」與「identity-pool-id」的預設值。 38 | 39 | 恭喜您!您想在應該已經擁有可運作的參考架構範例。您可以即時接受投票、調整您的 DynamoDB 以處理不同層級的外來流量,以及在您的儀表板即時觀察結果的變化。 40 | 41 | ## 請注意 42 | 43 | AWS CloudFormation 指令碼將為您建立兩個 DynamoDB 資料表。雖然您可以透過 AWS CloudFormation 指令碼指定讀取與寫入容量,但無法指定指令碼中的資料表名稱。這是因為接受與彙整投票的 JavaScript 程式碼必須事先知道資料表的名稱 (_VoteApp_ 與 _VoteAppAggregates_)。如果您要變更您的 DynamoDB 資料表的名稱,請務必變更其在 JavaScript 檔案中的名稱,其位於可在 [彙整原始碼](/lambda-functions/aggregate-votes/) 與 [接受原始碼](/lambda-functions/receive-vote/) 中找到的程式碼。 44 | 45 | ## 清除 46 | 47 | 若要移除所有已自動建立的資源,請刪除 AWS CloudFormation 堆疊。您必須手動移除 API Gateway 終端節點與 Amazon Cognito Identity Pool。 48 | 49 | 注意:除非在刪除堆疊之前已移除儲存貯體中的所有檔案,否則刪除 S3 儲存貯體將會失敗。 50 | 51 | ## 授權 52 | 53 | 此參考架構範例依據 Apache 2.0 授權。 54 | -------------------------------------------------------------------------------- /apigateway-mappingtemplate.txt: -------------------------------------------------------------------------------- 1 | { 2 | #foreach( $token in $input.path('$').split('&') ) 3 | #set( $keyVal = $token.split('=') ) 4 | #set( $keyValSize = $keyVal.size() ) 5 | #if( $keyValSize >= 1 ) 6 | #set( $key = $util.urlDecode($keyVal[0]) ) 7 | #if( $keyValSize >= 2 ) 8 | #set( $val = $util.urlDecode($keyVal[1]) ) 9 | #else 10 | #set( $val = '' ) 11 | #end 12 | "$key": "$val"#if($foreach.hasNext),#end 13 | #end 14 | #end 15 | } 16 | -------------------------------------------------------------------------------- /error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Error Page 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
32 | 33 |
34 | 35 |
36 |
37 |

My Vote App

38 |
39 |
40 | 41 |
42 |

Oops.

43 |

We're sorry, something went wrong.

44 |
45 | 46 |
47 |
48 |

Demo created for AWS Startup Collection on Medium.

49 |
50 |
51 | 52 |
53 | 54 |
55 | 56 |
57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Vote App 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
31 |

VoteApp

32 |

Text Your Vote For RED, GREEN, or BLUE to

33 |

(123) 456-7890

34 |

This is a simple demonstration of Lambda, a compute service from AWS that runs your code in response to events.

35 |
36 | 37 |
38 |
39 |
40 | 41 |
42 |
43 |

Lambda monitors a DynamoDB table, which is populated with votes generated by texting RED, BLUE, or GREEN to a phone number provided by our friends at Twilio. 44 | When the table is updated, Lambda invokes code to query the table and aggregate the votes, which are used to create the graph above. Read more at https://medium.com/aws-activate-startup-blog.

45 |
46 |
47 | 48 | 51 | 52 |
53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /lambda-functions/aggregate-votes/app.js: -------------------------------------------------------------------------------- 1 | console.log('Loading event'); 2 | var AWS = require('aws-sdk'); 3 | var dynamodb = new AWS.DynamoDB(); 4 | 5 | exports.handler = function(event, context) { 6 | 7 | var totalRed = 0; 8 | var totalGreen = 0; 9 | var totalBlue = 0; 10 | 11 | event.Records.forEach(function(record) { 12 | 13 | var votedForHash = record.dynamodb['NewImage']['VotedFor']['S']; 14 | var numVotes = record.dynamodb['NewImage']['Votes']['N']; 15 | 16 | // Determine the color on which to add the vote 17 | if (votedForHash.indexOf("RED") > -1) { 18 | votedFor = "RED"; 19 | totalRed += parseInt(numVotes); 20 | } else if (votedForHash.indexOf("GREEN") > -1) { 21 | votedFor = "GREEN"; 22 | totalGreen += parseInt(numVotes); 23 | } else if (votedForHash.indexOf("BLUE") > -1) { 24 | votedFor = "BLUE"; 25 | totalBlue += parseInt(numVotes); 26 | } else { 27 | console.log("Invalid vote: ", votedForHash); 28 | } 29 | }); 30 | 31 | // Update the aggregation table with the total of RED, GREEN, and BLUE 32 | // votes received from this series of updates 33 | 34 | var aggregatesTable = 'VoteAppAggregates'; 35 | if (totalRed > 0) updateAggregateForColor("RED", totalRed); 36 | if (totalBlue > 0) updateAggregateForColor("BLUE", totalBlue); 37 | if (totalGreen > 0) updateAggregateForColor("GREEN", totalGreen); 38 | 39 | console.log('Updating Aggregates Table', totalRed); 40 | 41 | function updateAggregateForColor(votedFor, numVotes) { 42 | console.log("Updating Aggregate Color ", votedFor); 43 | console.log("For NumVotes: ", numVotes); 44 | 45 | dynamodb.updateItem({ 46 | 'TableName': aggregatesTable, 47 | 'Key': { 'VotedFor' : { 'S': votedFor }}, 48 | 'UpdateExpression': 'add #vote :x', 49 | 'ExpressionAttributeNames': {'#vote' : 'Vote'}, 50 | 'ExpressionAttributeValues': { ':x' : { "N" : numVotes.toString() } } 51 | }, function(err, data) { 52 | if (err) { 53 | console.log(err); 54 | context.fail("Error updating Aggregates table: ", err) 55 | } else { 56 | console.log("Vote received for %s", votedFor); 57 | context.succeed("Successfully processed " + event.Records.length + " records."); 58 | } 59 | }); 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /lambda-functions/receive-vote/README.MD: -------------------------------------------------------------------------------- 1 | Install requirements with `npm install` 2 | -------------------------------------------------------------------------------- /lambda-functions/receive-vote/app.js: -------------------------------------------------------------------------------- 1 | console.log('Loading event'); 2 | var AWS = require('aws-sdk'); 3 | var dynamodb = new AWS.DynamoDB(); 4 | 5 | exports.handler = function(event, context) { 6 | var twilio = require('twilio'); 7 | var dynamodb = new AWS.DynamoDB({apiVersion: '2012-08-10', region: 'us-east-1'}); 8 | 9 | /* Make sure we have a valid vote (one of [RED, GREEN, BLUE]) */ 10 | console.log(event); 11 | var votedFor = event['Body'].toUpperCase().trim(); 12 | if (['RED', 'GREEN', 'BLUE'].indexOf(votedFor) >= 0) { 13 | /* Add randomness to our value to help spread across partitions */ 14 | votedForHash = votedFor + "." + Math.floor((Math.random() * 10) + 1).toString(); 15 | /* ...updateItem into our DynamoDB database */ 16 | var tableName = 'VoteApp'; 17 | dynamodb.updateItem({ 18 | 'TableName': tableName, 19 | 'Key': { 'VotedFor' : { 'S': votedForHash }}, 20 | 'UpdateExpression': 'add #vote :x', 21 | 'ExpressionAttributeNames': {'#vote' : 'Votes'}, 22 | 'ExpressionAttributeValues': { ':x' : { "N" : "1" } } 23 | }, function(err, data) { 24 | if (err) { 25 | console.log(err); 26 | context.fail(err); 27 | } else { 28 | var resp = new twilio.TwimlResponse(); 29 | resp.message("Thank you for casting a vote for " + votedFor); 30 | context.done(null, [resp.toString()]); 31 | console.log("Vote received for %s", votedFor); 32 | } 33 | }); 34 | } else { 35 | console.log("Invalid vote received (%s)", votedFor); 36 | context.fail("Invalid vote received"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lambda-functions/receive-vote/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VoteApp", 3 | "version": "0.0.0", 4 | "description": "VoteApp Demo using API Gateway and Lambda", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "jeffnunn@amazon.com", 10 | "dependencies": { 11 | "twilio": ">= 2.0.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lambda_webapp.template: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | 4 | "Description" : "AWS CloudFormation Template for VoteApp: Builds DynamoDB tables, an S3 bucket, and Lambda functions for use in a real-time voting application. ** This template creates multiple AWS resources. You will be billed for the AWS resources used if you create a stack from this template.", 5 | 6 | "Parameters": { 7 | 8 | "S3BucketName": { 9 | "Description": "S3 bucket in which the static app will reside", 10 | "Type": "String", 11 | "MinLength": "3", 12 | "MaxLength": "63", 13 | "Default": "myvoteappbucket" 14 | }, 15 | 16 | "LambdaS3Bucket" : { 17 | "Description" : "Name of S3 bucket where static site and Lambda function packages are stored.", 18 | "Type" : "String", 19 | "Default" : "awslambda-reference-architectures" 20 | }, 21 | 22 | "LambdaReceiveS3Key" : { 23 | "Description" : "Name of S3 key for ZIP with Lambda function package that receives votes.", 24 | "Type" : "String", 25 | "Default" : "web-app/receive.zip" 26 | }, 27 | 28 | "LambdaAggregateS3Key" : { 29 | "Description" : "Name of S3 key for ZIP with Lambda function package that aggregates votes.", 30 | "Type" : "String", 31 | "Default" : "web-app/aggregate.zip" 32 | }, 33 | 34 | "VotesTableRead": { 35 | "Description": "Read capacity units for VoteApp DynamoDB table", 36 | "Type": "String", 37 | "MinLength": "1", 38 | "MaxLength": "4", 39 | "AllowedPattern": "[0-9]*", 40 | "Default": "1" 41 | }, 42 | 43 | "VotesTableWrite": { 44 | "Description": "Write capacity units for VoteApp DynamoDB table", 45 | "Type": "String", 46 | "MinLength": "1", 47 | "MaxLength": "4", 48 | "AllowedPattern": "[0-9]*", 49 | "Default": "1" 50 | }, 51 | 52 | "AggregatesTableRead": { 53 | "Description": "Read capacity units for VoteAppAggregates aggregates table", 54 | "Type": "String", 55 | "MinLength": "1", 56 | "MaxLength": "4", 57 | "AllowedPattern": "[0-9]*", 58 | "Default": "1" 59 | }, 60 | 61 | "AggregatesTableWrite": { 62 | "Description": "Write capacity units for VoteAppAggregates aggregates table", 63 | "Type": "String", 64 | "MinLength": "1", 65 | "MaxLength": "4", 66 | "AllowedPattern": "[0-9]*", 67 | "Default": "1" 68 | } 69 | }, 70 | 71 | "Resources": { 72 | 73 | "DynamoDBTable": { 74 | "Type": "AWS::DynamoDB::Table", 75 | "Properties": { 76 | "AttributeDefinitions": [ 77 | { 78 | "AttributeName": "VotedFor", 79 | "AttributeType": "S" 80 | } 81 | ], 82 | "KeySchema": [ 83 | { 84 | "AttributeName": "VotedFor", 85 | "KeyType": "HASH" 86 | } 87 | ], 88 | "ProvisionedThroughput": { 89 | "ReadCapacityUnits": { 90 | "Ref": "VotesTableRead" 91 | }, 92 | "WriteCapacityUnits": { 93 | "Ref": "VotesTableWrite" 94 | } 95 | }, 96 | "TableName": "VoteApp" 97 | } 98 | }, 99 | 100 | "DynamoDBAggregatesTable": { 101 | "Type": "AWS::DynamoDB::Table", 102 | "Properties": { 103 | "AttributeDefinitions": [ 104 | { 105 | "AttributeName": "VotedFor", 106 | "AttributeType": "S" 107 | } 108 | ], 109 | "KeySchema": [ 110 | { 111 | "AttributeName": "VotedFor", 112 | "KeyType": "HASH" 113 | } 114 | ], 115 | "ProvisionedThroughput": { 116 | "ReadCapacityUnits": { 117 | "Ref": "AggregatesTableRead" 118 | }, 119 | "WriteCapacityUnits": { 120 | "Ref": "AggregatesTableWrite" 121 | } 122 | }, 123 | "TableName": "VoteAppAggregates" 124 | } 125 | }, 126 | 127 | "S3Bucket": { 128 | "Type": "AWS::S3::Bucket", 129 | "Properties": { 130 | "AccessControl": "PublicRead", 131 | "BucketName": { 132 | "Ref": "S3BucketName" 133 | }, 134 | "WebsiteConfiguration": { 135 | "IndexDocument": "index.html", 136 | "ErrorDocument": "error.html" 137 | } 138 | } 139 | }, 140 | 141 | "BucketPolicy" : { 142 | "Type" : "AWS::S3::BucketPolicy", 143 | "Properties" : { 144 | "PolicyDocument" : { 145 | "Id" : "S3BucketPolicy", 146 | "Version": "2012-10-17", 147 | "Statement": [ 148 | { 149 | "Sid": "PublicReadForGetBucketObjects", 150 | "Effect": "Allow", 151 | "Principal": { 152 | "AWS": "*" 153 | }, 154 | "Action": "s3:GetObject", 155 | "Resource" : { "Fn::Join" : [ 156 | "", [ "arn:aws:s3:::", { "Ref" : "S3Bucket" } , "/*" ] 157 | ] } 158 | } 159 | ] 160 | }, 161 | "Bucket" : { "Ref" : "S3Bucket" } 162 | } 163 | }, 164 | 165 | "LambdaVoteFunction": { 166 | "Type": "AWS::Lambda::Function", 167 | "Properties": { 168 | "Code": { 169 | "S3Bucket": { 170 | "Ref": "LambdaS3Bucket" 171 | }, 172 | "S3Key": { 173 | "Ref": "LambdaReceiveS3Key" 174 | } 175 | }, 176 | "Runtime": "nodejs", 177 | "Description": "Receives votes from Twilio and adds to DynamoDB", 178 | "Handler": "app.handler", 179 | "Role": { 180 | "Fn::GetAtt": [ 181 | "LambdaExecDynamoRole", 182 | "Arn" 183 | ] 184 | }, 185 | "Timeout": "30" 186 | } 187 | }, 188 | 189 | "LambdaAggregateFunction": { 190 | "Type": "AWS::Lambda::Function", 191 | "Properties": { 192 | "Code": { 193 | "S3Bucket": { 194 | "Ref": "LambdaS3Bucket" 195 | }, 196 | "S3Key": { 197 | "Ref": "LambdaAggregateS3Key" 198 | } 199 | }, 200 | "Runtime": "nodejs", 201 | "Description": "Receives updated items from DynamoDB streams for aggregation", 202 | "Handler": "app.handler", 203 | "Role": { 204 | "Fn::GetAtt": [ 205 | "LambdaExecDynamoRole", 206 | "Arn" 207 | ] 208 | }, 209 | "Timeout": "30" 210 | } 211 | }, 212 | 213 | "LambdaExecDynamoRole": { 214 | "Type": "AWS::IAM::Role", 215 | "Properties": { 216 | "AssumeRolePolicyDocument": { 217 | "Version": "2012-10-17", 218 | "Statement": [ 219 | { 220 | "Effect": "Allow", 221 | "Principal": { 222 | "Service": "lambda.amazonaws.com" 223 | }, 224 | "Action": "sts:AssumeRole" 225 | } 226 | ] 227 | }, 228 | "Policies": [ 229 | { 230 | "PolicyName": "lambda_exec_role_voteapp", 231 | "PolicyDocument": { 232 | "Version": "2012-10-17", 233 | "Statement": [ 234 | { 235 | "Effect": "Allow", 236 | "Action": [ 237 | "logs:CreateLogGroup", 238 | "logs:CreateLogStream", 239 | "logs:PutLogEvents" 240 | ], 241 | "Resource": [ 242 | "arn:aws:logs:*:*:*" 243 | ] 244 | }, 245 | { 246 | "Effect": "Allow", 247 | "Action": [ 248 | "dynamodb:GetItem", 249 | "dynamodb:PutItem", 250 | "dynamodb:Query", 251 | "dynamodb:UpdateItem" 252 | ], 253 | "Resource": "*" 254 | } 255 | ] 256 | } 257 | } 258 | ] 259 | } 260 | } 261 | }, 262 | 263 | "Outputs": { 264 | 265 | "WebsiteURL": { 266 | "Description": "URL for static website hosted on S3", 267 | "Value": { 268 | "Fn::GetAtt": [ 269 | "S3Bucket", 270 | "WebsiteURL" 271 | ] 272 | } 273 | }, 274 | 275 | "S3BucketSecureURL": { 276 | "Description": "Name of S3 bucket hosting content", 277 | "Value": { 278 | "Fn::Join": [ 279 | "", 280 | [ 281 | "https://", 282 | { 283 | "Fn::GetAtt": [ 284 | "S3Bucket", 285 | "DomainName" 286 | ] 287 | } 288 | ] 289 | ] 290 | } 291 | } 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /mapping.txt: -------------------------------------------------------------------------------- 1 | ## convert HTML FORM POST data to JSON for insertion directly into a Lambda function 2 | 3 | ## get the raw post data from the AWS built-in variable and give it a nicer name 4 | #set($rawPostData = $input.path('$')) 5 | 6 | ## first we get the number of "&" in the string, this tells us if there is more than one key value pair 7 | #set($countAmpersands = $rawPostData.length() - $rawPostData.replace("&", "").length()) 8 | 9 | ## if there are no "&" at all then we have only one key value pair. 10 | ## we append an ampersand to the string so that we can tokenise it the same way as multiple kv pairs. 11 | ## the "empty" kv pair to the right of the ampersand will be ignored anyway. 12 | #if ($countAmpersands == 0) 13 | #set($rawPostData = $rawPostData + "&") 14 | #end 15 | 16 | ## now we tokenise using the ampersand(s) 17 | #set($tokenisedAmpersand = $rawPostData.split("&")) 18 | 19 | ## we set up a variable to hold the valid key value pairs 20 | #set($tokenisedEquals = []) 21 | 22 | ## now we set up a loop to find the valid key value pairs, which must contain only one "=" 23 | #foreach( $kvPair in $tokenisedAmpersand ) 24 | #set($countEquals = $kvPair.length() - $kvPair.replace("=", "").length()) 25 | #if ($countEquals == 1) 26 | #set($kvTokenised = $kvPair.split("=")) 27 | #if ($kvTokenised[0].length() > 0) 28 | ## we found a valid key value pair. add it to the list. 29 | #set($devNull = $tokenisedEquals.add($kvPair)) 30 | #end 31 | #end 32 | #end 33 | 34 | ## next we set up our loop inside the output structure "{" and "}" 35 | { 36 | #foreach( $kvPair in $tokenisedEquals ) 37 | ## finally we output the JSON for this pair and append a comma if this isn't the last pair 38 | #set($kvTokenised = $kvPair.split("=")) 39 | "$kvTokenised[0]" : #if($kvTokenised[1].length() > 0)"$kvTokenised[1]"#{else}""#end#if( $foreach.hasNext ),#end 40 | #end 41 | } 42 | -------------------------------------------------------------------------------- /narrow.css: -------------------------------------------------------------------------------- 1 | /* Space out content a bit */ 2 | html, 3 | body { 4 | background-color: #333; 5 | color: #fff; 6 | text-align: center; 7 | text-shadow: 0 1px 3px rgba(0,0,0,.5); 8 | padding-top: 20px; 9 | padding-bottom: 20px; 10 | } 11 | 12 | /* Everything but the jumbotron gets side spacing for mobile first views */ 13 | .header, 14 | .marketing, 15 | .footer { 16 | padding-right: 15px; 17 | padding-left: 15px; 18 | } 19 | 20 | /* Custom page header */ 21 | .header { 22 | border-bottom: 1px solid #e5e5e5; 23 | } 24 | /* Make the masthead heading the same height as the navigation */ 25 | .header h3 { 26 | padding-bottom: 19px; 27 | margin-top: 0; 28 | margin-bottom: 0; 29 | line-height: 40px; 30 | } 31 | 32 | /* Custom page footer */ 33 | .footer { 34 | padding-top: 19px; 35 | color: #777; 36 | border-top: 1px solid #e5e5e5; 37 | } 38 | 39 | /* Customize container */ 40 | @media (min-width: 768px) { 41 | .container { 42 | max-width: 730px; 43 | } 44 | } 45 | .container-narrow > hr { 46 | margin: 30px 0; 47 | } 48 | 49 | /* Main marketing message and sign up button */ 50 | .jumbotron { 51 | text-align: center; 52 | border-bottom: 1px solid #e5e5e5; 53 | } 54 | .jumbotron .btn { 55 | padding: 14px 24px; 56 | font-size: 21px; 57 | } 58 | 59 | /* Supporting marketing content */ 60 | .marketing { 61 | margin: 40px 0; 62 | } 63 | .marketing p + h4 { 64 | margin-top: 28px; 65 | } 66 | 67 | /* Responsive: Portrait tablets and up */ 68 | @media screen and (min-width: 768px) { 69 | /* Remove the padding we set earlier */ 70 | .header, 71 | .marketing, 72 | .footer { 73 | padding-right: 0; 74 | padding-left: 0; 75 | } 76 | /* Space out the masthead */ 77 | .header { 78 | margin-bottom: 30px; 79 | } 80 | /* Remove the bottom border on the jumbotron for visual effect */ 81 | .jumbotron { 82 | border-bottom: 0; 83 | } 84 | } -------------------------------------------------------------------------------- /refresh.js: -------------------------------------------------------------------------------- 1 | /* Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use 4 | this file except in compliance with the License. A copy of the License is 5 | located at 6 | 7 | http://aws.amazon.com/apache2.0/ 8 | 9 | or in the "license" file accompanying this file. This file is distributed on an 10 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 11 | implied. See the License for the specific language governing permissions and 12 | limitations under the License. */ 13 | 14 | // Region and IdentityPoolId should be set to your own values 15 | AWS.config.region = ''; // Region 16 | AWS.config.credentials = new AWS.CognitoIdentityCredentials({ 17 | IdentityPoolId: '', 18 | }); 19 | 20 | var dynamodb = new AWS.DynamoDB(); 21 | var params = { TableName: 'VoteAppAggregates' }; 22 | 23 | /* Create the context for applying the chart to the HTML canvas */ 24 | var ctx = $("#graph").get(0).getContext("2d"); 25 | 26 | /* Set the options for our chart */ 27 | var options = { segmentShowStroke : false, 28 | animateScale: true, 29 | percentageInnerCutout : 50, 30 | showToolTips: true, 31 | tooltipEvents: ["mousemove", "touchstart", "touchmove"], 32 | tooltipFontColor: "#fff", 33 | animationEasing : 'easeOutCirc' 34 | } 35 | 36 | /* Set the initial data */ 37 | var init = [ 38 | { 39 | value: 1, 40 | color: "#e74c3c", 41 | highlight: "#c0392b", 42 | label: "Red" 43 | }, 44 | { 45 | value: 1, 46 | color: "#2ecc71", 47 | highlight: "#27ae60", 48 | label: "Green" 49 | }, 50 | { 51 | value: 1, 52 | color: "#3498db", 53 | highlight: "#2980b9", 54 | label: "Blue" 55 | } 56 | ]; 57 | 58 | graph = new Chart(ctx).Doughnut(init, options); 59 | 60 | $(function() { 61 | getData(); 62 | $.ajaxSetup({ cache: false }); 63 | /* Get the data every 3 seconds */ 64 | setInterval(getData, 3000); 65 | }); 66 | 67 | /* Makes a scan of the DynamoDB table to set a data object for the chart */ 68 | function getData() { 69 | dynamodb.scan(params, function(err, data) { 70 | if (err) { 71 | console.log(err); 72 | return null; 73 | } else { 74 | var redCount = 0; 75 | var greenCount = 0; 76 | var blueCount = 0; 77 | 78 | for (var i in data['Items']) { 79 | if (data['Items'][i]['VotedFor']['S'] == "RED") { 80 | redCount = parseInt(data['Items'][i]['Vote']['N']); 81 | } 82 | if (data['Items'][i]['VotedFor']['S'] == "GREEN") { 83 | greenCount = parseInt(data['Items'][i]['Vote']['N']); 84 | } 85 | if (data['Items'][i]['VotedFor']['S'] == "BLUE") { 86 | blueCount = parseInt(data['Items'][i]['Vote']['N']); 87 | } 88 | } 89 | 90 | var data = [ 91 | { 92 | value: redCount, 93 | color:"#e74c3c", 94 | highlight: "#c0392b", 95 | label: "Red" 96 | }, 97 | { 98 | value: greenCount, 99 | color: "#2ecc71", 100 | highlight: "#27ae60", 101 | label: "Green" 102 | }, 103 | { 104 | value: blueCount, 105 | color: "#3498db", 106 | highlight: "#2980b9", 107 | label: "Blue" 108 | } 109 | ]; 110 | 111 | /* Only update if we have new values (preserves tooltips) */ 112 | if ( graph.segments[0].value != data[0].value || 113 | graph.segments[1].value != data[1].value || 114 | graph.segments[2].value != data[2].value 115 | ) 116 | { 117 | graph.segments[0].value = data[0].value; 118 | graph.segments[1].value = data[1].value; 119 | graph.segments[2].value = data[2].value; 120 | graph.update(); 121 | } 122 | 123 | } 124 | }); 125 | } 126 | -------------------------------------------------------------------------------- /vote.css: -------------------------------------------------------------------------------- 1 | #graph { 2 | margin-bottom: 20px; 3 | } 4 | 5 | a { 6 | color: #ff9900; 7 | } 8 | 9 | .lead { 10 | color: #c6c6c6; 11 | } 12 | --------------------------------------------------------------------------------