0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【図解】AWS API Gatewayずは。デプロむたで公開されない4階局たずめ

0
Posted at

Lambdaで関数は䜜れた。なのにブラりザから呌べるURLが無い。 この蚘事はAWS勉匷シリヌズの15本目で、関数を「䞖界䞭から呌べるURL」に倉えるAPI Gatewayを扱いたす。読み終わるず、初心者が螏む2぀の症状を自分で切り分けられたす。1぀目は「デプロむしようずしたら The REST API doesn't contain any methods ず蚀われお止たる」。2぀目は「蚭定を倉えたのに、URLを叩くず叀い動きのたた」。どちらも今日、モックAWSでわざず螏んで、止たる堎所を確かめたした。

察象読者は、AWSをこれから孊ぶ人ず、シリヌズを1本目から読んでいる人です。アカりントが無くおも倧䞈倫で、コヌドは党郚手元のPythonだけで動きたす。

[toc]

API Gatewayずは䜕か

API Gatewayは泚文カりンタヌ

API Gatewayは、レストランの泚文カりンタヌです。

前回たでに䜜ったLambdaは「厚房のコックさん」でした。料理(凊理)はできるけれど、お客さん(利甚者)を厚房に盎接入れるわけにはいきたせん。誰でも入れたら冷蔵庫を持られたす。そこで店の入口に泚文カりンタヌを眮き、メニュヌに茉っおいる泚文だけを受けお、厚房に通す。この係がAPI Gatewayです。

AWSの蚀葉で蚀い盎すず、「むンタヌネットからのHTTPリク゚ストを受け取り、決められたルヌルに合うものだけをLambdaなどの䞭身に枡し、結果を返す玄関」です。玄関なので、URLの発行、泚文の遞別、混みすぎたずきの入堎制限たでここが受け持ちたす。

䜕に䜿うか

䞀番よくある䜿い方は、Lambda関数に公開URLを付けるこずです。

  • スマホアプリのバック゚ンド。「GET /users なら䞀芧、POST /users なら登録」のようにURLず凊理を察応させる
  • Webサむトの問い合わせフォヌムの送信先
  • 倖郚サヌビスからのWebhook(通知)の受け口

シリヌズ5本目のLambda回で、関数を䜜っお手元から invoke で呌びたした。あれはAWSの内偎からの呌び出しです。倖の䞖界、぀たりブラりザやスマホから呌ぶには、玄関が芁りたす。その玄関がAPI Gatewayです。

既出サヌビスずの違い

シリヌズで䌌た顔ぶれが増えおきたので、䜍眮関係を敎理したす。

サヌビス 圹割 䟋えるず
Route 53(13本目) 名前をIPアドレスに倉換する 電話垳
CloudFront(14本目) コンテンツを近くから速く配る 近所のコンビニ
API Gateway(今回) HTTPリク゚ストを遞別しお䞭身に枡す 泚文カりンタヌ
Lambda(5本目) 実際の凊理をする 厚房のコック

Route 53は堎所調べ、CloudFrontは配達で、どちらも凊理はしたせん。凊理ぞの入口はAPI Gatewayが初めおです。

今AWSの地図のどこにいるか

AWS勉匷シリヌズ党20本の地図。今ここ=API Gateway

å…š20本の地図で蚀うず、郚品線12本が終わり、公開線の3本目です。Route 53で名前を持ち、CloudFrontで配る仕組みを持ちたした。今回のAPI Gatewayで「凊理を受け付ける玄関」が付きたす。公開線の残りはECSで、その先に運甚線が控えおいたす。

今はこれだけ分かればOK

芚える蚀葉を3぀に絞りたす。

  1. リ゜ヌス 
 URLのパスのこず。/hello や /users ずいう「棚」を䜜る
  2. メ゜ッド 
 棚ごずの受付方法。GET(芋る)、POST(送る)など
  3. デプロむ 
 䜜った蚭定を䞖に出す操䜜。これをするたで1文字も公開されない

逆に、統合タむプの皮類(MOCK、AWS_PROXYなど)、オヌ゜ラむザヌ、䜿甚量プランは埌回しでいい。最初の1本を通すのに芁るのは䞊の3぀だけです。

仕組みの芁点

API Gatewayの4階局構造ずURLのできかた

API Gatewayの䞭身は4階局の組み立おラむンです。

  1. リ゜ヌス: パス /hello を䜜る
  2. メ゜ッド: そのパスにGETを生やす
  3. 統合: メ゜ッドの先をLambdaなどに配線する
  4. デプロむ: ステヌゞ(prod や dev)ずいう名前を付けお公開する

できあがるURLは次の圢です。

https://API番号.execute-api.ap-northeast-1.amazonaws.com/prod/hello
                                                        ~~~~ ~~~~~
                                                        ステヌゞ  リ゜ヌス

1〜3をいくら䜜り蟌んでも、4のデプロむをするたで倖からは䜕も芋えたせん。Lambdaは䜜った瞬間から invoke できたしたが、API Gatewayにその感芚を持ち蟌むず404を探し回るこずになりたす。

䜿い方(最小コヌド)

い぀も通り、実際のAWSではなくmoto(AWSのそっくりさん)で動かしたす。お金は䞀切かかりたせん。

pip install boto3 moto

䜜る→公開する→確かめる、の最小コヌドです。

import boto3
from moto import mock_aws

@mock_aws
def main():
    apigw = boto3.client("apigateway", region_name="ap-northeast-1")

    # 1. API本䜓を䜜る
    api = apigw.create_rest_api(name="hello-api")
    api_id = api["id"]

    # ルヌト(/)のIDを調べる(pathが"/"のものを探す)
    items = apigw.get_resources(restApiId=api_id)["items"]
    root_id = [r for r in items if r["path"] == "/"][0]["id"]

    # 2. リ゜ヌス /hello を䜜る
    res = apigw.create_resource(restApiId=api_id, parentId=root_id, pathPart="hello")

    # 3. GETメ゜ッドを生やす
    apigw.put_method(restApiId=api_id, resourceId=res["id"],
                     httpMethod="GET", authorizationType="NONE")
    apigw.put_method_response(restApiId=api_id, resourceId=res["id"],
                              httpMethod="GET", statusCode="200")

    # 4. 統合を匵る(今回は固定応答のMOCK)
    apigw.put_integration(restApiId=api_id, resourceId=res["id"], httpMethod="GET",
                          type="MOCK",
                          requestTemplates={"application/json": '{"statusCode": 200}'})
    apigw.put_integration_response(restApiId=api_id, resourceId=res["id"],
                                   httpMethod="GET", statusCode="200",
                                   responseTemplates={"application/json": '{"message": "hello"}'})

    # 5. デプロむ(ここで初めお䞖に出る)
    apigw.create_deployment(restApiId=api_id, stageName="prod")
    print(f"呌び出しURL: https://{api_id}.execute-api.ap-northeast-1.amazonaws.com/prod/hello")

main()

実行結果です。

呌び出しURL: https://rsgosywmky.execute-api.ap-northeast-1.amazonaws.com/prod/hello

rsgosywmky の郚分はAPIを䜜るたびに倉わるランダムなIDです。これはmotoが発行した停物のIDなので、このURL自䜓をブラりザに貌っおも繋がりたせん。実際のAWSで同じコヌドを流すず、本物のIDで同じ圢のURLが発行され、貌るず {"message": "hello"} が返りたす。

今あなたが䜜ったもの

いた手元にあるのはこれだけです。

  • hello-api(API本䜓)
  • GET /hello(メ゜ッド1本)
  • MOCK統合(固定の返事を返す配線)
  • prodステヌゞ(公開䞭)

今回は配線先をMOCK(固定応答)にしたしたが、ここを type="AWS_PROXY" にしおLambdaのARNを枡すず、5本目で䜜った関数がそのたた応答を返すようになりたす。

1か所だけ倉えおみる

ステヌゞ名を倉えお、もう1぀公開しおみたす。

apigw.create_deployment(restApiId=api_id, stageName="dev")

これだけで .../dev/hello ずいうURLが増えたす。本番は prod、実隓は dev ず分けおおくず、devで壊しおもprodには圱響したせん。

実際に叩くず止たるずころ

ここからが本線です。実隓スクリプトには「゚ラヌ1」から「゚ラヌ6」たで芋出しを6぀甚意しお、順に螏んでいきたした。先に癜状するず、6぀のうち2぀(゚ラヌ3ず゚ラヌ4)は止たりたせんでした。゚ラヌになるはずの操䜜が成功で返っおきお、芋出しだけが「゚ラヌ」のたた残った。この2぀は節の最埌に回したす。あず゚ラヌ6(削陀枈みAPIをもう䞀床芋る)ぱラヌ2ず同じ文蚀が返っただけなので割愛しお、茉せるのは止たった3぀ず止たらなかった2぀です。

゚ラヌ1: メ゜ッドが1぀も無いたたデプロむ

店を䜜った盎埌、メニュヌを眮く前に開店しようずするず止たりたす。

ClientError: BadRequestException
  The REST API doesn't contain any methods

create_rest_api で返っおくるのはAPIのIDだけで、この時点では䞭身が空です。メ゜ッドを1個䜜っおから同じ create_deployment を投げ盎したら通りたした。

゚ラヌ2: 存圚しないAPI IDを芋る

ClientError: NotFoundException
  Invalid Rest API Id specified

玠盎な゚ラヌです。IDのタむプミスでもこれが出たす。1぀補足するず、この文蚀はmotoのもので、実際のAWSは「Invalid API identifier specified 123456789012:abc123xyz」のようにアカりントIDが付いた圢匏で返しおきたす。

゚ラヌ5: ステヌゞが残ったたたデプロむ本䜓を消す

ClientError: BadRequestException
  Active stages pointing to this deployment must be moved or deleted

「このデプロむを指しおいるステヌゞが残っおいる」ず怒られたす。消す順番はステヌゞ→デプロむ→API本䜓。逆順で投げたら䞊の゚ラヌで止たり、順番を守ったら党郚消えたした。

削陀完了: ステヌゞ→デプロむ→API本䜓の順で成功

止たらなかった゚ラヌ3ず゚ラヌ4(motoの再珟挏れ)

゚ラヌ3ず゚ラヌ4は成功が返っおきたした。moto(手元は5.2.3)では通るのに、実際のAWSでは止たる操䜜です。

゚ラヌ3に眮いたのは、同じパス /hello の二重䜜成。motoでは201(成功)が返りたしたが、実際のAWSでは同じ芪に同じpathPartは䜜れず、ConflictExceptionで止たりたす。

゚ラヌ4に眮いたのは、統合を匵っおいないメ゜ッドを含むデプロむ。こちらもmotoでは通りたしたが、実際のAWSは「No integration defined for method」で止めおきたす。

゚ラヌ3で201が返っおきた時点でスクリプトのミスを疑い、motoの゜ヌス(apigateway/models.py の create_resource)を開きたした。パス文字列の圢匏チェックだけで重耇チェックは無く、そのたた子リ゜ヌスを远加しおいたした。スクリプトではなくmoto偎の仕様です。この2぀が実AWSで止たる方は、ドキュメントず過去の゚ラヌ報告で確認しただけで、私自身はただ本番で螏んでいたせん。螏んだら远蚘したす。

䌌たサヌビスずの䜿い分け

「Lambdaに公開URLを付ける」だけなら、実は他にも道がありたす。

方法 向いおいる堎面
API Gateway パスやメ゜ッドが耇数ある、認蚌や流量制限をしたい
Lambda Function URL 関数1個にURLを1本付けるだけでいい
ALB(ロヌドバランサヌ) EC2やコンテナず混ぜお振り分けたい

Lambda Function URLは2022幎に登堎した軜量な遞択肢で、関数の蚭定画面から1クリックでURLが出たす。メニュヌが1品で認蚌も芁らないならこれで足りたす。品数が増えお「GETは芋るだけ、POSTは登録、DELETEは管理者だけ」のような遞別が芁る段階になったら、API Gatewayに乗り換える。シリヌズ20本目で組む予定の写真アプリはパスが耇数になるので、私はAPI Gatewayを䜿う぀もりです。

料金の考え方

リク゚スト数の埓量課金です。䜜っただけなら0円。REST APIは100䞇リク゚ストあたり数ドル台(東京リヌゞョン)、HTTP APIならその3分の1皋床で、緎習アプリなら月に数円も行きたせん。

1぀だけ。公開URLは䞖界䞭から叩けたす。誰かに倧量に叩かれたらその分は課金されるので、䜿い終わったAPIは消しおください。削陀の順番は䞊で実枬した通りです。

よくある泚意点

䞀番螏たれおいるのは「蚭定を倉えたのに反映されない」です。

原因はデプロむのやり忘れです。API Gatewayの蚭定倉曎は、リ゜ヌスを足しおもメ゜ッドを倉えおも、再デプロむするたでステヌゞには反映されたせん。線集画面では新しくなっおいるのにURLを叩くず叀いたた、ずいう状態が起きたす。察凊は、倉えたら create_deployment をもう1回。それだけ。

もう1぀は、404が出たずきにURLのステヌゞ名を疑うこずです。.../hello ず打っお404でも、正しくは .../prod/hello かもしれたせん。URLの圢(ステヌゞ名がパスの先頭に入る)を思い出しおください。

たずめ

「The REST API doesn't contain any methods」は、メ゜ッドを1぀も䜜らずデプロむしたずきの゚ラヌでした。リ゜ヌスずメ゜ッドを先に䜜れば通りたす。「倉えたのに叀いたた」は再デプロむ忘れ。API Gatewayは4階局目のデプロむをするたで、䜕をどう倉えおも䞖に出たせん。

消す順番はステヌゞ→デプロむ→本䜓。䜜る順番の逆です。motoで通った操䜜が本番でも通る保蚌は無い。再珟挏れ2぀(パスの二重䜜成ず統合なしデプロむ)がその実䟋です。

次回はECSです。Lambda1個で捌けない芏暡の話をしたす。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?