2021/03時点での情報です。AWSのコンソール画面や仕様は頻繁に変更されるので注意してください。
AWSのサービスであるLambdaとAPI Gatewayを使ってサーバーレスのWeb APIを作成したので備忘録として手順をまとめておきます。
間違えていたら教えていただけるとありがたいです。
ゴール
AWS LambdaとAmazon API Gatewayを利用してHTTPプロトコルのGET/POSTで呼び出せる単純なWeb APIを作成すること。
やらないこと
- AWS自体や他のサービスの説明
- 最低限のコード以外の実装
APIの仕様
パラメーターの値を簡単に加工して返すだけのシンプルなAPIです。
GET/POST共通
パラメーター名 | 値 |
---|---|
name | 名前を入力します |
age | 年齢を入力します。 |
レスポンス
// nameとageにはパラメーターで渡した値が代入されます。
{
"answer": "My name is ${name}, I am ${age} years old."
}
AWS Lambdaとは
AWS Lambda はサーバーレスコンピューティングサービスで、サーバーのプロビジョニングや管理、ワークロード対応のクラスタースケーリングロジックの作成、イベント統合の維持、ランタイムの管理を行わずにコードを実行できます。Lambda を使用すれば、実質どのようなタイプのアプリケーションやバックエンドサービスでも管理を必要とせずに実行できます。コードを ZIP ファイルまたはコンテナイメージとしてアップロードするだけで、Lambda はあらゆる規模のトラフィックに対して、自動的かつ正確にコンピューティング実行能力を割り当て、受信リクエストやイベントに基づいてコードを実行します。コードは、140 の AWS のサービスから自動的にトリガーするよう設定することも、ウェブやモバイルアプリケーションから直接呼び出すよう設定することもできます。Lambda 関数をお気に入りの言語 (Node.js、Python、Go、Java など) で記述し、サーバーレスツールと AWS SAM や Docker CLI などのコンテナツールの両方を使用して、関数をビルド、テスト、デプロイできます。(公式より)
だいたいこんな感じ
- サーバーを建てないでコード(関数)を実行できるよ
- コードはいろんな言語で書けるよ
- 勝手に適切なCPUリソースを割り当ててくれるよ
- アプリケーションや他のAWSのサービスから作成した関数を呼び出せるよ
単一の関数をアップロードして独立して実行できるサービスです。
Amazon API Gatewayとは
フルマネージド型サービスの Amazon API Gateway を利用すれば、開発者は規模にかかわらず簡単に API の作成、公開、保守、モニタリング、保護を行えます。API は、アプリケーションがバックエンドサービスからのデータ、ビジネスロジック、機能にアクセスするための「フロントドア」として機能します。API Gateway を使用すれば、リアルタイム双方向通信アプリケーションを実現する RESTful API および WebSocket API を作成することができます。API Gateway は、コンテナ化されたサーバーレスのワークロードやウェブアプリケーションをサポートします。
だいたいこんな感じ
- 外部からHTTPプロトコルを通じてサービスを呼び出せるURLを作成してくれるよ
- 受け取ったリクエストを他のサービスに渡してくれるよ
- バージョン管理やモニタリングとか色々できるよ
今回の実装部分
Lambdaファンクションの作成・コードの実装
Lambdaで作成する関数の単位はファンクションです。
ファンクションを作成してコードを実装(もしくはアップロード)します。
ファンクション作成
Lambdaサービスのページから Functions
> Create Function
をクリック
-
Author from scratch
を選択 -
Function name
にファンクション名を作成 -
Runtime
でコードを書く言語を指定(今回はNode.jsで書きます) -
Create Function
をクリック
これでファンクションが作成できたので中身を実装していきます。
ファンクションのコード実装
今回はコンソールで直接コードを書きます。
すると下にFunction code
エリアが現れるのでここにコードを書いていきます。
GETの(クエリパラメーターを受け取る)場合の実装
HTTPリクエストをGETで受け取った場合、API Gatewayから渡されるevent
変数のqueryStringParameters
にクエリパラメーターが格納されています。
なのでまずはGETリクエストを受け取った際のコードを実装してみます。
exports.handler = async (event) => {
const name = event.queryStringParameters.name
const age = event.queryStringParameters.age
return {
"statusCode": 200,
"headers": {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET"
},
"body": `{ "answer": "My name is ${name}, I am ${age} years old." }`,
"isBase64Encoded": false
}
}
ポイントは先程言ったとおりevent.queryStringParameters
からパラメーターが取得できるというところと、レスポンスの形式です。
後ほど紹介しますが、API GatewayとLambdaの連携方法としてLambdaプロキシ統合
という方法を使用します。
この方法で連携する場合にはレスポンスは以下の形式で返す必要があります。
{
"isBase64Encoded" : "boolean",
"statusCode": "number",
"headers": { ... },
"body": "JSON string"
}
デプロイ・テスト
コードを実装したらDeploy
を押してください。
コードがデプロイされて実行可能になります。
それではテストパラメーターを設定してテストを行います。
Test
ボタンを押します。
Configure test eventが開きます。
Create new test event
を選択してイベント名を指定、パラメーターを入力します。(スクショではすでに作成済みなのでEdit saved test events
が選択されています。)
プロキシ統合
の形式に合わせてパラメーターを指定します。
{
"queryStringParameters": {
"name": "Akumachan",
"age": "100030"
}
}
Create
を押してポップアップが閉じたら再度Test
を押してテストを実行します。
実行結果が表示されました。イージー!
POSTの(リクエストボディを受け取る)場合の実装
HTTPリクエストをPOSTで受け取った場合、API Gatewayから渡されるevent
変数のbody
にクエリパラメーターが格納されています。
event.body
は文字列形式で格納されているようなのでJSONでリクエストボディを送信している場合はJSON.parse
してパラメーターにアクセスします。
と、その前にメソッドによって処理を変えるコードを挿入します。
メソッドの種類はevent.httpMethod
に格納されているのでメソッドごとに分岐します。
※(2021/03/06)下記コード修正しました。API GatewayでHTTP APIを作成した場合とREST APIを作成した場合でevent
内のHTTPメソッドが書いてある場所が違いました。HTTP APIの場合はevent.requestContext.http.method
で、REST APIの場合はevent.httpMethod
のようです。
exports.handler = async (event) => {
let name, age
if ([event.httpMethod, event.requestContext.http.method].includes('GET')) {
name = event.queryStringParameters.name
age = event.queryStringParameters.age
} else if ([event.httpMethod, event.requestContext.http.method].includes('POST')) {
// Return response for POST request
} else {
// Return error.
}
return {
statusCode: 200,
body: `{ "answer": "My name is ${name}, I am ${age} years old." }`,
}
}
それではPOSTリクエストボディからパラメーターを取り出してname
とage
に代入します。
exports.handler = async (event) => {
let name, age
if ([event.httpMethod, event.requestContext.http.method].includes('GET')) {
name = event.queryStringParameters.name
age = event.queryStringParameters.age
} else if ([event.httpMethod, event.requestContext.http.method].includes('POST')) {
const body = JSON.parse(event.body)
name = body.name
age = body.age
} else {
// Return error.
}
return {
statusCode: 200,
body: `{ "answer": "My name is ${name}, I am ${age} years old." }`,
}
}
レスポンスの形式は共通のコードなので、これでテストを実行してみましょう。Deploy
を押してデプロイを完了してください。
テスト
Test
の横の▼をクリックしてConfigure test event
をクリック、Create new test event
からパラメーターを指定します。
{
"httpMethod": "POST",
"body": "{\"name\": \"AkumachanPOST\",\"age\": \"100032\"}"
}
Create
ボタンを押してポップアップが閉じたらTest
をクリックして実行します。
これでPOSTリクエストからのリクエストも処理できるようになりました。
次回に続く。