Amazon API Gatewayは、AWS Lambdaと組み合わせて使用することが一般的で、サーバーレスアーキテクチャを構築するための基盤として利用されています。WEBアプリを色々と作ろうとしている段階で、このAmazon API Gatewayを避けて通ることはないと思うので、この機能を理解して、使う時に引っかかるであろうポイントをまとめようと思います。
目次
- Application Programming Interface(API)とは
- Amazon API Gatewayとは
- Amazon API Gateway(REST API)を使ってみる
- まとめ
Application Programming Interface(API)とは
分かっているようで分かっていない気がするので改めて、確認します。
APIは、アプリケーションやサービスとやり取りをするための標準的なインターフェースのことです。プログラムが他のプログラムやサービスと情報を共有するために使用され、APIを使用することで、異なるプログラムやサービス間でデータを共有することができ、相互運用性や拡張性を向上させることができます。
APIの種類
APIは、異なる種類のアプリケーションやサービスで使用されます。Web API、REST API、SOAP API等の多様な種類のAPIがあります。APIは、標準化された規格に従って設計されることが多く、APIの利用者がアクセスしやすいように、ドキュメント化され、公開されることが一般的です。
Web API
APIというとWeb APIを指すことが大部分で、Webブラウザ経由でアクセスするAPIのことを指します。
HTTPプロトコルを使用してリクエストを送信し、JSON、XML、またはプレーンテキストの形式で応答を受け取ることができます。
APIというと「アプリケーションやサービスとやり取りをするための標準的なインターフェース」のことなので、ローカル環境でもこのワードに該当するサービスを作れば、APIと呼ぶものになるので、単純なAPIとWeb APIだとワードの範囲が違うんだなと理解しました。
Representational State Transfer(REST API)
Web APIと並列で考えてよいのかが怪しいのですが、RESTアーキテクチャスタイルであるWEB APIを指します。
- アドレス指定可能なURIで公開されていること
- インターフェース(HTTPメソッドの利用)の統一がされていること
- ステートレスであること
- 処理結果がHTTPステータスコードで通知されること
ステートレスとは、システムが現在の状態を表すデータなどを保持せず、入力の内容によってのみ出力が決定される方式。同じ入力に対する出力は常に同じになる。
これらの原則に則ったWebサービスをRESTfulなサービスといいます。
Web APIと同じように、HTTPプロトコルを使用して通信してデータをやり取りしますが、REST APIは、リソースの操作を表現するためにHTTPメソッド(後述: POST, GET, PUTなど)を使用する点が、Web APIとは異なるようです。
詳細は以下に載っていました。
RESTful API とは? - RESTful API の説明 - AWS
Amazon API Gatewayとは
Amazon API GatewayはAWS内でのAPIの作成および諸々の管理を行えるサービスのこと。基本これ単体で使うのではなく、AWS Lambda等とつなげて、リクエストに対して結果を返すサービスを作るの目的に使われます。
ちなみに、公式だと以下の説明が載っています。
Amazon API Gateway(規模に応じた API の作成、維持、保護)| AWS
フルマネージド型サービスの Amazon API Gateway を利用すれば、デベロッパーは規模にかかわらず簡単に API の作成、公開、保守、モニタリング、保護を行えます。API は、アプリケーションがバックエンドサービスからのデータ、ビジネスロジック、機能にアクセスするための「フロントドア」として機能します。API Gateway を使用すれば、リアルタイム双方向通信アプリケーションを実現する RESTful API および WebSocket API を作成することができます。API Gateway は、コンテナ化されたサーバーレスのワークロードやウェブアプリケーションをサポートします。
APIのタイプ
APIタイプは以下から選択ができ、それぞれの特徴は以下の通りです。
HTTP API | Web Socket API | REST API |
HTTP APIは、HTTPリクエスト/レスポンスを使用してRESTfulなWebサービスを作成するためのAPI。機能を絞ることで、REST APIよりも低レイテンシかつ低コスト(コスト最適化)を実現できるようです。 | WebSocket APIは、リアルタイムなWebアプリケーションを構築するためのAPIです。WebSocket APIは、クライアントとサーバー間で長時間の接続を確立することができ、データの双方向通信を可能にします。WebSocket APIは、リアルタイムな情報の伝達が必要なチャットアプリ、オンラインゲーム、監視システムなどに適しています。 | REST APIは、HTTPプロトコルに基づいたAPIで、HTTP APIの違いは色々とあるが、HTTPメソッド(GET、POST、PUT、DELETEなど)を使用してリソースの操作を実行します点が大きな差かなと思っています。 |
目的に応じて選択が必要です。私の場合、JSON形式でデータ送信したいので、HTTP API/REST APIから選択ができ、HTTPメソッドを用いて簡単に開発したいならばREST APIを選ぶ感じかなと思います。
REST APIのHTTPメソッド
REST APIタイプは以下から選択ができ、それぞれの特徴は以下の通りです。
メソッド | 説明 |
GET | Webページや画像などリソースを取得するために使用する |
POST | リソースを送信するために使用する |
PUT | リソースの更新や作成をするために使用する |
DELETE | リソースを削除するために使用する |
PATCH | リソースの一部を更新するために使用する |
HEAD | リソースのヘッダ情報のみを取得するために使用する |
OPTIONS | リソースに対して許可されているHTTPメソッドの一覧を取得するために使用する |
ANY | 一般的なHTTPメソッドではなくAWS API Gatewayで使われる概念で、すべてのHTTPメソッドを扱うことができる |
なんとなくは分かりましたが・・扱えるようになるため、実際に使ってみます。
Amazon API Gateway(REST API)を使ってみる
実際に使う前に、理解した範囲で知識をまとめます。
統合リクエスト設定
統合リクエストは、API Gatewayがバックエンドに送るHTTPリクエストで、クライアントから送信されたリクエストデータを渡して、必要に応じて変更します。今回はAWS Lambdaに渡すことを前提とします。設定方法は、以下にまとめられています。
API Gateway で Lambda プロキシ統合を設定する - Amazon API Gateway
メソッドリクエストから、クエリパラメータを受け取って、Lambdaに渡したい場合は、クエリパラメータを登録する必要がある。
統合リクエストから、マッピングテンプレートを登録する。今回は、JSON形式で受け取りたいので、以下の通り3つのパラメータ(my_param1, my_param2, my_param3)をもらう設定を追加。
クエリパラメータの設定方法
URLにクエリパラメータを付与する場合は、ルールに従って以下のように書く必要がある。
- パラメータはURLの後に「?」をつけて記載
- 各パラメータは「名前=値」で記載
- 複数パラメータを付与する場合は、「&」で分ける
書き方(3つのパラメータmy_param1, my_param2, my_param3を付与するケース) URL(https://*******)?my_param1=1&my_param2=2&my_param3=3
URLはデプロイしたHTTPメソッドのエンドポイントに設定する。
エンドポイントとは、クライアントとAPIとが通信をするための窓口であり、APIのリクエスト先になる。
プロキシ統合設定について
HTTPメソッドを作成する際に、「Lambdaプロキシ統合の使用」というチェックボックスがあり、この役割を説明する。
詳しくは以下にまとめられていたが、以下のように理解しました。
統合 | 非統合 |
API GatewayはLambda関数に直接接続され、API GatewayがHTTPリクエストをLambda関数に直接ルーティングするため、API GatewayとLambda関数の間の通信が最適化されます。Lambdaから返される値のフォーマットが決まっている | API GatewayとLambdaは独立して動作します。API GatewayはHTTPリクエストを受け取り、Lambda関数を呼び出すためにLambda関数のARN(Amazonリソース名)を設定します。Lambda関数はリクエストを処理し、結果をAPI Gatewayに返します。API GatewayはLambda関数からのレスポンスを返信し、クライアントに返します。Lambdaから返される値にフォーマットはなくそのままの値が返される |
動作を確認
環境設定に関しては、以下の通りで、Lambda関数は「statusCode」「body("Hello World")」「event(リクエスト)」を返す関数であり、API Gateway側ではANYメソッドがリクエストデータをそのままLambda関数に渡す設定になっている。プロキシ統合は非統合の設定。
Lambda関数
import json def lambda_handler(event, context): return { 'statusCode': 200, 'body': json.dumps('Hello World'), 'event': json.dumps(event) }
GET
ローカルにて以下コードを実行して、出力結果を確認した。
import requests import json pattern = "GET" URL = r"エンドポイント" payload = {'my_param1':"1", 'my_param2':2, 'my_param3':3} if pattern == "GET": print("GET") response = requests.get(URL, params=payload) data = response.json() print ("json", json.dumps(data, indent=4)) print("status_code",response.status_code) # ステータスコード取得 print("HTML_text", response.text) # HTMLを文字列で取得 print("binary", response.content) # HTMLをバイナリ形式で取得
出力結果は以下の通りで、eventは何もない状態で返されている。クエリとして、3つのパラメータを送付しているが、クエリパラメータを受け取る設定にしていないため、こういった現象が起きている。
GET json { "statusCode": 200, "body": "\"Hello World\"", "event": "{}" } status_code 200 HTML_text {"statusCode": 200, "body": "\"Hello World\"", "event": "{}"} binary b'{"statusCode": 200, "body": "\\"Hello World\\"", "event": "{}"}'
上記で説明した通り、統合リクエスト設定にてマッピングテンプレートを設定すると、以下の通り、受け取ることができて、Lambda関数に適切に渡されていることが確認できる。
# マッピングテンプレート設定後 GET json { "statusCode": 200, "event": "{\"my_param1\": \"1\", \"my_param2\": \"2\", \"my_param3\": \"3\"}" } status_code 200 HTML_text {"statusCode": 200, "body": "\"Hello World\"", "event": "{\"my_param1\": \"1\", \"my_param2\": \"2\", \"my_param3\": \"3\"}"} binary b'{"statusCode": 200, "body": "\\"Hello World\\"", "event": "{\\"my_param1\\": \\"1\\", \\"my_param2\\": \\"2\\", \\"my_param3\\": \\"3\\"}"}'
POST
ローカルにて以下コードを実行して、出力結果を確認した。
import requests import json pattern = "POST" URL = r"エンドポイント" payload = {'my_param1':"1", 'my_param2':2, 'my_param3':3} if pattern == "POST": print("POST") response = requests.post(URL, data=json.dumps(payload)) data = response.json() print ("json", json.dumps(data, indent=4)) print("status_code",response.status_code) # ステータスコード取得 print("HTML_text", response.text) # HTMLを文字列で取得 print("binary", response.content) # HTMLをバイナリ形式で取得
出力結果は以下の通りで、POSTメソッドの場合はマッピングテンプレートの設定をせずパラメータを送付して、Lambda関数に適切に渡されていることが確認できる。
POST json { "statusCode": 200, "body": "\"Hello World\"", "event": "{\"my_param1\": \"1\", \"my_param2\": 2, \"my_param3\": 3}" } status_code 200 HTML_text {"statusCode": 200, "body": "\"Hello World\"", "event": "{\"my_param1\": \"1\", \"my_param2\": 2, \"my_param3\": 3}"} binary b'{"statusCode": 200, "body": "\\"Hello World\\"", "event": "{\\"my_param1\\": \\"1\\", \\"my_param2\\": 2, \\"my_param3\\": 3}"}'
HEAD
ローカルにて以下コードを実行して、出力結果を確認した。
import requests import json pattern = "HEAD" URL = r"エンドポイント" payload = {'my_param1':"1", 'my_param2':2, 'my_param3':3} if pattern == "HEAD": print("HEAD") response = requests.head(URL) #data = response.json() #print ("json", json.dumps(data, indent=4)) print(response) print("status_code",response.status_code) # ステータスコード取得 print("HTML_text", response.text) # HTMLを文字列で取得 print("binary", response.content) # HTMLをバイナリ形式で取得
出力結果は以下の通りで、HEADメソッドでは、レスポンスボディを返さないため、 response.content などでレスポンスボディを取得することはできません。HEADメソッドは、サーバーからのレスポンスボディを取得することがないため、GETメソッドよりも高速にリソースの存在確認を行うことができます。
HEAD <Response [200]> status_code 200 HTML_text binary b''
他のメソッドに関しては、実際にWEBアプリを作った際に色々と確認しようと思う。一旦はここまで。
まとめ
APIに関する言葉の意味からスタートして、色々と勉強になりましたが、まだまだ奥が深く知識を浅いことを痛感しました。
HTTPメソッドは、Webアプリケーション開発において非常に重要な役割を果たしているので、使い方を勉強して、WEBアプリケーション作りに活かしていきたいと思います。