AWS Lambda入門③(Node編)〜API Gatewayで関数を公開する〜


概要

Api Gatewayとは

  • API GatewayはAWSが提供するサービスでHTTPでアクセス可能なAPIを作成できるサービスです
  • AWSの様々なサービスの呼び出しができるのでクライアントからするとLambdaなどをHTTPアクセスで実行するような感覚で使うことができます

API GatewayでLambda関数を公開する

Hello関数を公開してみる

  • まずは前回までで作ってあるHello関数を公開してみます
  • serverless.ymlに設定を追加します
serverless.yml
# ...省略

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

# ...省略
  • handlerの下にいくつか追加しました
    • pathはアクセスするときのpathです
    • methodはアクセスするときのHTTPメソッドです
  • 簡単ですね!

ローカルで動作確認

  • デプロイする前にまずはローカルで動作確認します
  • API Gatewayをローカルで動かすために必要なライブラリを追加します
yarn add -D serverless-offline@next

serverless-offlineのドキュメントは2020/3/5時点でα版の6系で書かれているとのことなので@nextをつけて6系をインストールする

  • serverless.ymlに設定を追加します
serverless.yml
# ...省略
plugins:
  - serverless-offline # 追加した行
  - serverless-dynamodb-local
custom:
  serverless-offline: # 追加した行
    httpPort: 8083 # 追加した行
  dynamodb:
    stages: dev
    start:
      port: 8082
      inMemory: true
      migrate: true
      seed: true
    seed:
      hello:
        sources:
          - table: ${self:provider.environment.DYNAMODB_TABLE}-hello
            sources: [./seeds/hello.json]
# ...省略
  • pluginsserverless-offlineを追加しました
  • customにサーバ起動時のポート番号を追加しました
    • デフォルトは3000です
  • 以下のコマンドでサーバを起動します
sls offline start
  • ログにURLが表示されているはずです
   ┌───────────────────────────────────────────┐
   │                                           │
   │   GET | http://localhost:8083/dev/hello   │
   │                                           │
   └───────────────────────────────────────────┘
  • 今回はREST Clientを使って動作確認します

  • うまくいけば画像のような結果になっているはずです
  • Lambdaを直接叩いていた時はstatusCodemessageの2つが返ってきていましたが今回はmessageだけです
  • statusCodeはAPI GatewayがHTTPレスポンスのステータスコードとしてセットして返却してくれています

AWSにデプロイして動作確認

  • ローカルで確認できたのでAWSにデプロイします
  • いつも通りServerlessFrameworkのコマンドを使います
sls deploy
  • デプロイに成功すると作成されたAPIのURLがログに出力されます
    • こんな感じ
Serverless: Stack update finished...
Service Information
service: sls-sample
stage: dev
region: ap-northeast-1
stack: sls-sample-dev
resources: 24
api keys:
  None
endpoints:
  GET - https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/hello
functions:
  hello: sls-sample-dev-hello
  put: sls-sample-dev-put
  get: sls-sample-dev-get
  query: sls-sample-dev-query
  getAll: sls-sample-dev-getAll
layers:
  None
Serverless: Run the "serverless" command to setup monitoring, troubleshooting and testing.
✨  Done in 351.49s.
  • REST Clientでアクセスして確認します

  • ステータスコード200で成功しました
  • これでhello関数を世の中に公開することができました

全ての関数を公開する

  • hello関数と同じように残りの関数も公開してみましょう

API Gatewayの設定追加

  • serverless.ymlを修正します
serverless.yml
# ...省略

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get
  put:
    handler: handler.put
    environment:
      tableName: ${self:provider.environment.DYNAMODB_TABLE}-hello
    events:
      - http:
          path: messages
          method: post
  get:
    handler: handler.get
    environment:
      tableName: ${self:provider.environment.DYNAMODB_TABLE}-hello
    events:
      - http:
          path: messages/{id}
          method: get
  getAll:
    handler: handler.getAll
    environment:
      tableName: ${self:provider.environment.DYNAMODB_TABLE}-hello
    events:
      - http:
          path: messages
          method: get
# ...省略
  • functionの項目にそれぞれURLとHTTPメソッドを追加しました
    • getのpathはmessages/{id}とすることでidをURLで指定するようにしました
  • 関数を一部修正します
    • get関数がURLに埋め込まれたidを取得できるようする
    • put関数が渡されたパラメータを取得できるようにする
handler.js
// ...省略
module.exports.get = async event => {
  const { id } = event.pathParameters; // この行を修正
  const params = {
    TableName: tableName,
    Key: { id },
  };

  try {
    const result = await dynamo.get(params).promise();
    return {
      statusCode: 200,
      body: JSON.stringify(result.Item),
    };
  } catch (error) {
    return {
      statusCode: error.statusCode,
      body: error.message,
    };
  }
};
// ...省略
module.exports.put = async event => {
  const id = String(Date.now());
  const { message } = JSON.parse(event.body); // この行を修正

  const params = {
    TableName: tableName,
    Item: { id, message },
  };

  try {
    await dynamo.put(params).promise();
    return {
      statusCode: 200,
      body: JSON.stringify({ id, message }),
    };
  } catch (error) {
    return {
      statusCode: error.statusCode,
      body: error.message,
    };
  }
};
// ...省略

ローカルで動作確認

  • ローカルサーバを立ち上げます
    • ローカルのDBを見に行くようにLOCAL=trueをつけて環境変数を設定しておきます
    • 詳しくは前回のDynamo編をご参照ください
LOCAL=true sls offline start
  • ログにURLが出力されます
   ┌────────────────────────────────────────────────────┐
   │                                                    │
   │   GET  | http://localhost:8083/dev/hello           │
   │   POST | http://localhost:8083/dev/messages        │
   │   GET  | http://localhost:8083/dev/messages/{id}   │
   │   GET  | http://localhost:8083/dev/messages        │
   │                                                    │
   └────────────────────────────────────────────────────┘
  • REST Clientでアクセスしてみましょう
  • それぞれ成功すると以下のようになるはずです



AWSで動作確認

  • AWSにデプロイしてREST Clientでアクセスしてみましょう
sls deploy
  • 関数の文だけURLが表示されます
endpoints:
  GET  - https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/hello
  POST - https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/messages
  GET  - https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/messages/{id}
  GET  - https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/messages
functions:
  hello: sls-sample-dev-hello
  put: sls-sample-dev-put
  get: sls-sample-dev-get
  getAll: sls-sample-dev-getAll
  • REST Clientでアクセスしてみてください
  • キャプチャは省略しますがローカルのときと同じようにアクセスできていればOKです

まとめ

  • API Gatewayを使うことでHTTリクエストでLambda関数を実行できました
  • ServerlessFrameworkを使うと簡単にAPI Gatewayの設定をすることができます
  • ローカルで動作させるためのライブラリも整っているため開発もやりやすくていいですね