まるっとワーク

データ分析・電子工作など気になることを残していきます

Amazon API Gatewayを理解する

Amazon API Gatewayは、AWS Lambdaと組み合わせて使用することが一般的で、サーバーレスアーキテクチャを構築するための基盤として利用されています。WEBアプリを色々と作ろうとしている段階で、このAmazon API Gatewayを避けて通ることはないと思うので、この機能を理解して、使う時に引っかかるであろうポイントをまとめようと思います。

目次

Application Programming Interface(API)とは

分かっているようで分かっていない気がするので改めて、確認します。
APIは、アプリケーションやサービスとやり取りをするための標準的なインターフェースのことです。プログラムが他のプログラムやサービスと情報を共有するために使用され、APIを使用することで、異なるプログラムやサービス間でデータを共有することができ、相互運用性や拡張性を向上させることができます。

APIの種類

APIは、異なる種類のアプリケーションやサービスで使用されます。Web APIREST APISOAP API等の多様な種類のAPIがあります。APIは、標準化された規格に従って設計されることが多く、APIの利用者がアクセスしやすいように、ドキュメント化され、公開されることが一般的です。

Web API

APIというとWeb APIを指すことが大部分で、Webブラウザ経由でアクセスするAPIのことを指します。
HTTPプロトコルを使用してリクエストを送信し、JSONXML、またはプレーンテキストの形式で応答を受け取ることができます。

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

Simple Object Access Protoco(SOAP API)

SOAPは、HTTPプロトコルの代わりに独自のプロトコルを使用してXML形式でデータをやり取りしてAPI操作を表現します。独自のプロトコルを使うという点とXML形式を使うという点で、Web APIREST APIと異なり、SOAPの方が複雑な設定が必要であることから、比較的重いプロトコルであり、通信速度が遅くなります。ただし、セキュリティや信頼性に優れるという利点があり、主に企業間のシステム間の通信に使用されることが多いようです。

Amazon API Gatewayとは

Amazon API GatewayAWS内での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から返される値にフォーマットはなくそのままの値が返される

qiita.com

動作を確認

環境設定に関しては、以下の通りで、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)
    }


AWS API Gateway

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}"}'

ローカルにて以下コードを実行して、出力結果を確認した。

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アプリケーション作りに活かしていきたいと思います。