在第二章中,我们将尝试使用Serverless框架来实践【无服务器架构】,重点是API Gateway的使用

尝试在serverless框架中试用【无服务器架构】第二章 〜使用API Gateway编写API篇〜

あらすじ – 情节简介

今年的花粉真是厉害。我一直处于微热的状态。

自从加入公司后,已经过去了大约两年时间。
从这次开始,我想要以系列形式公开一下正在热议中的“无服务器架构”这个话题。

推荐您将此保存起来,因为以后通常会根据请求进行更新。

我在某公司担任CTO,但我认为与其只学习理论性的知识,不如学习能够模糊地把握概念,并通过实践来加深知识,这样学习起来更加高效。

作为一种教育风格,我们并不是僵化地教授正确的知识,而是以使没有经验的人能够大致理解为目标,来构建教材。

我将使用以下系列作品的主题来继续。

那么,让我们再次开始吧!

首先

让我们尝试使用serverless框架中的nodejs模板,并使用AWS APIGateway的endpoint,就像之前在第1章中试用【无服务器架构】时的文章一样。

那么,我们开始吧

环境

Mac环境

10.11.6

节点环境

$ nodebrew ls

v0.12.14
$ nodebrew install-binary v7.4.0
$ nodebrew ls
v0.12.14
v7.4.0

Python 环境

$ pyenv versions
  system
  2.7.12
$ pyenv install -v 3.5.2
$ eval "$(pyenv init -)"
$ pyenv shell 3.5.2
$ python --version
Python 3.5.2

AWSCLI环境

$ pip install awscli
$ aws --version
aws-cli/1.11.9 Python/2.7.10 Darwin/15.6.0 botocore/1.4.66

无服务器环境

$ npm install serverless -g
$ serverless --version
1.5.1

创建项目

我会继续使用在之前【服务器无架构】通过serverless框架尝试的第一章《使用nodejs的模板》创建的名为”serverlesstest”的AWS配置文件。

让我们像往常一样使用serverless命令在nodejs中创建一个名为apigateway的项目。

$ serverless create --template aws-nodejs --provider aws --profile serverlesstest --path apigateway --verbose

创建的项目

apigateway
├── handler.js
└── serverless.yml

使用API网关

更改设置

$ cd ~/Documents/apigateway
$ ls .
handler.js
serverless.yml

让我们尝试使用API Gateway通过将Lambda的阶段设置为测试,并使用默认的测试脚本。更改的部分如下:
这次我们将以显示diff结果的形式进行更好的体验。
由于一开始可能无法理解,请同时附上最后的文件状态。

--- serverless.yml.before   2017-03-06 18:26:48.000000000 +0900
+++ serverless.yml.after    2017-03-06 19:00:41.000000000 +0900
@@ -20,6 +20,9 @@
 provider:
   name: aws
   runtime: nodejs4.3
+  profile: serverlesstest
+  stage: test
+  region: ap-northeast-1

 # you can overwrite defaults here
 #  stage: dev
@@ -56,7 +59,12 @@
 functions:
   hello:
     handler: handler.hello
-
+    events:
+      - http:
+          path: hello
+          method: get
+          cors: true
+
 #    The following are a few example events you can configure
 #    NOTE: Please make sure to change your handler code to work with those events
 #    Check the event documentation for details

修改后的文件(只摘录更改部分)

provider:
  name: aws
  runtime: nodejs4.3
  profile: serverlesstest
  stage: test
  region: ap-northeast-1

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get
          cors: true

部署

修正完成后,请尝试部署。

$ serverless deploy --provider aws --profile serverlesstest -v

当部署顺利部署完成后,将显示以下信息,请复制 endpoints 部分的网址。

确认API Gateway的信息。

Service Information
service: apigateway
stage: test
region: ap-northeast-1
api keys:
  None
endpoints:
  GET - https://xxxxxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/test/hello
functions:
  apigateway-test-hello: arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxxxx:function:apigateway-test-hello

Stack Outputs
HelloLambdaFunctionArn: arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxxxx:function:apigateway-test-hello
HelloLambdaFunctionQualifiedArn: arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxxxx:function:apigateway-test-hello:1
ServiceEndpoint: https://xxxxxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/test
ServerlessDeploymentBucketName: apigateway-test-xxxxxxxxxxxxxx

用浏览器尝试访问。

让我们尝试在浏览器中访问刚才复制的端点URL。如果显示如下图所示,表示成功。

ブラウザでAPIGateWayのエンドポイントにアクセスした結果

稍稍倒数一下,我尝试访问DynamoDB。

计划下一次创建一个访问DynamoDB的Restful API,
但我有点急于行动,所以这次也访问DynamoDB并读取结果吧。
解释的程度减少一些,就像平时一样。

使用serverless.yml

    • Lambdaで実行するユーザーにDynamoDBの周りの権限を付与(iamRoleStatementsらへん)

 

    resourcesでDynamoDBの設定も同時に設定

设定中。

修改serverless.yml

--- serverless.yml.before   2017-03-06 19:00:41.000000000 +0900
+++ serverless.yml.after    2017-03-07 10:52:00.000000000 +0900
@@ -23,6 +23,17 @@
   profile: serverlesstest
   stage: test
   region: ap-northeast-1
+  iamRoleStatements:
+  - Effect: Allow
+    Action:
+      - dynamodb:DescribeTable
+      - dynamodb:Query
+      - dynamodb:Scan
+      - dynamodb:GetItem
+      - dynamodb:PutItem
+      - dynamodb:UpdateItem
+      - dynamodb:DeleteItem
+    Resource: "arn:aws:dynamodb:ap-northeast-1:*:*"

 # you can overwrite defaults here
 #  stage: dev
@@ -57,14 +68,14 @@
 #    - exclude-me-dir/**

 functions:
-  hello:
-    handler: handler.hello
+  readAll:
+    handler: handler.readAll
     events:
       - http:
-          path: hello
+          path: members
           method: get
           cors: true
-
+
 #    The following are a few example events you can configure
 #    NOTE: Please make sure to change your handler code to work with those events
 #    Check the event documentation for details
@@ -95,3 +106,21 @@
 #     NewOutput:
 #       Description: "Description for the output"
 #       Value: "Some output value"
+resources:
+  Resources:
+    MembersDynamoDbTable:
+      Type: 'AWS::DynamoDB::Table'
+      DeletionPolicy: Retain
+      Properties:
+        AttributeDefinitions:
+          -
+            AttributeName: id
+            AttributeType: S
+        KeySchema:
+          -
+            AttributeName: id
+            KeyType: HASH
+        ProvisionedThroughput:
+          ReadCapacityUnits: 1
+          WriteCapacityUnits: 1
+        TableName: 'members'

修改 handler.js

在下一章中,我考虑使用DynamoDB来创建一个Restful的API,但由于水平有限,所以我决定提前,在这一章中也使用DynamoDB访问数据,并创建一个获取结果的API。


--- handler.js.before   2017-03-06 14:47:50.000000000 +0900
+++ handler.js.after    2017-03-07 10:29:24.000000000 +0900
@@ -1,16 +1,17 @@
 'use strict';

-module.exports.hello = (event, context, callback) => {
-  const response = {
-    statusCode: 200,
-    body: JSON.stringify({
-      message: 'Go Serverless v1.0! Your function executed successfully!',
-      input: event,
-    }),
-  };
+const membersReadAll = require('./members-read-all.js');

-  callback(null, response);
+module.exports.readAll = (event, context, callback) => {
+  membersReadAll(event, (error, result) => {
+    const response = {
+      statusCode: 200,
+      headers: {
+        "Access-Control-Allow-Origin" : "*"
+      },
+      body: JSON.stringify(result),
+    };

-  // Use this code if you don't use the http event with the LAMBDA-PROXY integration
-  // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
+    context.succeed(response);
+  });
 };

创建 members-read-all.js

让我们使用Node.js的AWS SDK库来创建一个脚本,通过简单地使用DynamoDB的scan操作获取名为”members”的表的结果。

'use strict';

const AWS = require('aws-sdk');
const dynamoDb = new AWS.DynamoDB.DocumentClient();

module.exports = (event, callback) => {
  const params = {
    TableName: 'members',
  };

  return dynamoDb.scan(params, (error, data) => {
    if (error) {
      callback(error);
    }
    callback(error, data.Items);
  });
};

安装库

让我们安装在Node.js中使用的库。 这次我们不使用package.json等文件进行安装。

$ npm install aws-sdk --save

在此项目文件夹下创建了一个node_modules文件夹,保存了对应的库。

部署

挺长的时间呢。现在就实际部署一下吧。

$ serverless deploy --provider aws --profile serverlesstest -v

从部署结果中复制终端节点,并尝试通过浏览器访问。
https://xxxxxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/test/members

您显示了「[]」这个结果吗?

通过AWS控制台查看DynamoDB

DynamoDB

将数据存入DynamoDB。

为了避免确认数据为空的无聊行为,让我们从AWS控制台手动注册数据吧。

在DynamoDB表中创建项目
DynamoDBのテーブルに項目を作成する
将数据存入DynamoDB表中
DynamoDBのテーブルにデータを登録する

通过API网关查看DynamoDB的结果

让我们再次在浏览器中访问 https://xxxxxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/test/members ,检查是否能够获取到之前注册到DynamoDB中的值。

API Gatewayの結果

编辑后记

我稍稍提前完成了与DynamoDB的协作。由于只包含了显示API结果的部分作为段子,所以可能无法真正感受到其效果,但如果有余力的人可以尝试创建API使用方。

下一次,我计划尝试创建一个更加符合Restful风格的能够处理CRUD的API。请拭目以待。

bannerAds