ここまでのシリーズでは、API を呼ぶ人やプログラムが「誰か」を示すしくみを見てきました。API キー、トークン、証明書、そしてワークロード ID です。でも、API が10個、20個と増えると、それぞれの API で同じ確認を作るのは大変です。
そこで出てくるのが、API の入口を1つにまとめる「API ゲートウェイ」です。この記事では、ビルの総合受付のたとえを使いながら、Microsoft のドキュメントで確かめ、テスト用の環境で nginx を API ゲートウェイとして実際に動かした結果と一緒に、一歩ずつ図にしました。
- API ゲートウェイとは何か、なぜ入口を1つにまとめるのか
- ゲートウェイの役割(振り分け・確認・回数制限・記録など)と、似た機器との違い
- リクエストがゲートウェイを通る流れと、断るときの番号(401・404・429・502)
- nginx で、振り分け・キーの確認・回数制限・記録を試す方法
- Azure API Management の部品とポリシーの考え方
先に覚えておく3つの言葉
最初に、いちばん大事な3つの言葉を、ビルの受付にたとえて押さえておきます。
ほかにも、この記事にはいくつか専門の言葉が出てきます。先に、ざっくりした意味を並べておきます。読んでいて迷ったら、ここに戻ってきてください。
| 言葉 | ざっくりした意味 | 受付でたとえると |
|---|---|---|
| リバースプロキシ | リクエストを代わりに受け取って、奥のサーバに渡すしくみ | 取り次ぎ係 |
| ルーティング | パス(URL の後ろの部分)を見て、行き先を決めること | 行き先の案内 |
| オフロード | 各 API の共通の仕事を、入口が肩代わりすること | 入館証の確認を受付だけでする |
| 回数制限 | 決まった時間に呼べる回数を制限すること(レート制限) | 混んだら待ってもらう |
| ステータスコード | 結果を表す3桁の番号。200 は成功、401・404・429・502 などは失敗 | 受付の返事 |
この記事の地図
外から来るリクエストは、すべて API ゲートウェイを通ってから、奥の API に届きます。
先に全体の地図を見ておくと、迷いにくくなります。
左がAPI を呼ぶ側(スマホアプリ、取引先のシステム、社内のバッチなど)、右が実際に仕事をする API(バックエンド)です。真ん中のゲートウェイが、行き先を決め、誰かを確かめ、回数を見張り、記録を残します。奥の API は、自分の仕事だけに集中できます。
まずはたとえで:ビルの総合受付
API ゲートウェイは、API の世界の「総合受付」です。
大きなビルを思い浮かべてください。受付がないビルでは、来客は営業部や経理部の場所を自分で覚えておく必要があります。各部署は、それぞれ自分で入館証を確かめ、誰が来たかを記録します。部署ごとに確認のしかたも記録の形もばらばらです。
総合受付があるビルでは、来客は受付だけを知っていれば足ります。受付が入館証を確かめ、行き先を案内し、記録を残します。混んでいるときは、受付で少し待ってもらいます。各部署は、自分の仕事に集中できます。API ゲートウェイは、この総合受付の役目を、API の世界でするものです。
直接つなぐか、ゲートウェイを通すか
API が増えるほど、入口をまとめる効果が大きくなります。
大事な比較なので、先に並べておきます。
Microsoft の設計ガイド(Azure Architecture Center)は、API ゲートウェイを「クライアントとアプリケーションのサービスのやり取りを1か所で管理する入口」と説明しています。そして、ゲートウェイがない場合の困りごとを挙げています。かみ砕くと、次のとおりです。
| 困りごと | どういうことか | 受付でたとえると |
|---|---|---|
| 呼ぶ側が複雑になる | アプリが API の場所を全部覚え、失敗にもそれぞれ備える | 来客が部署の場所を全部覚える |
| 結びつきが強くなる | API の作りを変えると、呼ぶ側も直す必要がある | 部署が引っ越すと、来客に知らせ直す |
| 往復が増える | 1つの操作で、いくつもの API を呼ぶ | 書類をもらうのに部署を何か所も回る |
| 同じ仕事を何度も作る | 認証・TLS・回数制限を API ごとに作る | 部署ごとに入館証を確かめる |
| 攻撃される入口が増える | 外に見える入口の数だけ、守る場所が増える | 出入口がたくさんあるビル |
ゲートウェイの役割
ゲートウェイの仕事は、「振り分け」と「どの API にも共通する確認」の2つです。
Microsoft のドキュメントは、Azure API Management のゲートウェイがすることとして、次の6つを挙げています。ほかのゲートウェイ製品でも、だいたい同じです。
- API の呼び出しを受け取って、ふさわしいバックエンドに振り分ける
- API キーや、JWT・証明書などの資格情報を確かめる
- 使用量の上限(割り当て量)や回数制限を守らせる
- 必要に応じて、リクエストやレスポンスを変換する
- 設定すれば、レスポンスをキャッシュ(取っておいて使い回すこと)する
- 監視や調査のために、ログ・メトリクス・追跡の情報を出す
Microsoft の設計ガイドは、ゲートウェイに肩代わりさせられる仕事の例として、TLS の終端、mTLS、認証、IP アドレスの許可・拒否、回数制限、ログと監視、レスポンスのキャッシュ、WAF、圧縮などを挙げています。TLS や mTLS、API キーや JWT の検証など、このシリーズで見てきたものの多くを、入口でまとめて引き受けられるということです。
似た機器との違い
似た機器とは、「何が主役か」で見分けます。API ゲートウェイの主役は「API の管理」です。
| 機器 | 主な仕事 | 受付でたとえると |
|---|---|---|
| リバースプロキシ | リクエストを代わりに受け取り、奥に渡す。ゲートウェイの土台になる | 取り次ぎ係 |
| ロードバランサ | 同じ仕事をする何台かのサーバに、負荷を分ける | 同じ窓口を何か所か開けて、空いているほうへ案内する |
| WAF | 攻撃らしい中身の通信を見つけて止める(E-3 で扱います) | 手荷物検査 |
| API ゲートウェイ | API ごとに、誰か・回数・記録・変換を管理する | 総合受付 |
実際の製品は、いくつかの役割を兼ねていることが多く、組み合わせて置くこともあります。Microsoft の設計ガイドでも、nginx や HAProxy のようなリバースプロキシ、Azure Application Gateway(L7 の振り分け・TLS の終端・WAF を持つロードバランサ)、Azure API Management などが、API ゲートウェイを作る選択肢として並んでいます。
誰が何を持つか
利用者が知っているのは入口だけ。奥の API の場所は、ゲートウェイだけが知っています。
登場するのは、API を呼ぶ利用者のアプリ、API ゲートウェイ、バックエンド API、設定をする管理者の4つです。
受付でたとえると、来客が持っているのは「ビルの住所」と「入館証」だけです。各部署が何階にあるかは、受付の案内表にだけ書いてあります。部署の側は、受付を通った人だけを迎えます。裏口から勝手に入られないように、ネットワークの設定でゲートウェイ以外からの通信を受け付けないようにしておくことも大事です。
全体の流れ
ここからは、注文 API と商品 API の前にゲートウェイを置く例で、流れを順に見ます。準備、使うとき、断るときの3つです。
準備:振り分けとルールを登録する
あらすじ:管理者が、ゲートウェイに「振り分けの表」と「ルール」を登録し、利用者には「入口の URL」と「キー」だけを渡します。
| 手順 | 誰が・どこで | 何をするか | 物(設定・キー)はどうなるか |
|---|---|---|---|
| ① | 管理者・ゲートウェイで操作 | 振り分けを登録する | 「/orders/ は注文 API へ」という表ができる |
| ② | 管理者・ゲートウェイで操作 | ルールを登録する | キーの確認・回数制限・記録が決まる |
| ③ | 管理者・バックエンドで操作 | ゲートウェイからだけ受け付ける | 裏口をふさぐ |
| ④ | 管理者 → 利用者 | API キーを発行して渡す | 利用者ごとに別のキー |
| ⑤ | 管理者 → 利用者 | 入口の URL を伝える | ゲートウェイの URL だけ。奥の場所は伝えない |
| ⑥ | 利用者 | アプリに URL とキーを設定する | キーはシークレットとして扱う |
使うとき:入口で確かめてから、奥に渡す
あらすじ:リクエストはまずゲートウェイに届きます。ゲートウェイが行き先・誰か・回数を確かめ、ヘッダを整えてから、奥の API に渡します。
| 手順 | 誰が・どこで | 何をするか | 物(キー・ヘッダ)はどうなるか |
|---|---|---|---|
| ⑦ | アプリ → ゲートウェイ | キーを付けてリクエストを送る | キーは X-API-Key ヘッダに入る |
| ⑧ | ゲートウェイ | パスから行き先を決める | /orders/ なら注文 API |
| ⑨ | ゲートウェイ | キーから誰かを確かめる | 一覧と照らして app01 と分かる |
| ⑩ | ゲートウェイ | 回数を確かめる | app01 の回数を数える |
| ⑪ | ゲートウェイ | ヘッダを整える | キーは外し、「app01」と受付番号を付ける |
| ⑫ | ゲートウェイ → 注文 API | リクエストを渡す | キーは奥に届かない |
| ⑬ | 注文 API | 仕事をする | 「app01 からの依頼」として処理する |
| ⑭ | 注文 API → ゲートウェイ | レスポンスを返す | ― |
| ⑮ | ゲートウェイ | 記録する | 誰・どこ・結果・時間がログに残る |
| ⑯ | ゲートウェイ → アプリ | レスポンスを返す | ― |
⑪がポイントです。キーは入口で確かめたら役目が終わるので、奥には渡しません。奥に渡るのは「app01 から」という結果だけです。こうすると、奥の API のログなどにキーが残る心配もなくなります。受付で入館証を見たら、部署には「〇〇社の△△さんが来ました」とだけ伝えるのと同じです。
断るとき:入口で止めて、番号で知らせる
あらすじ:確認に通らないリクエストは、ゲートウェイがその場で断り、理由をステータスコード(番号)で返します。
| 番号 | 止まった場所(最初の図) | 意味 | 受付でたとえると |
|---|---|---|---|
| 401 | ⑨ 誰かを確かめる | キーがない・違う | 入館証がない |
| 429 | ⑩ 回数を確かめる | 短い間に呼びすぎ | 混んでいるので少し待って |
| 404 | ⑧ 行き先を決める | 登録のないパス | そんな部署はない |
| 502 | ⑫ 奥に渡す | 奥の API につながらない | 部署に誰もいない |
401・429・404 は、入口で止まるので、奥の API まで届きません。知らない相手や使いすぎの相手のリクエストを、奥の API は見ることさえありません。502 だけは、入口は通ったけれど奥でつまずいた、という意味です。429 は RFC 6585 で決まった番号で、「決まった時間に送るリクエストが多すぎる(レート制限)」ことを表します。502 は RFC 9110 で、ゲートウェイやプロキシが奥のサーバから正しい返事をもらえなかったことを表します。
ゲートウェイの3つの使い方
「振り分ける」「まとめる」「肩代わりする」の3つの使い方があります。
Microsoft の設計ガイドは、API ゲートウェイの使い方を3つのパターンにまとめています。
- ゲートウェイ ルーティング:1つの入口から、パスで各 API に振り分けます。呼ぶ側と API の結びつきを弱めたいときに使います。
- ゲートウェイ アグリゲーション:1回の呼び出しを受けて、ゲートウェイが裏で複数の API を呼び、結果をまとめて返します。呼ぶ側と API の往復を減らせます。
- ゲートウェイ オフロード:認証や TLS、記録など、どの API にも共通する仕事を入口に集めます。
この記事の「試してみる」では、ルーティングとオフロードを試します。
試してみる(nginx を API ゲートウェイにする)
ここからは、テスト用の環境で、nginx 1.24.0 を API ゲートウェイとして動かした結果を見ていきます。nginx は、Microsoft の設計ガイドでもゲートウェイの選択肢に挙がっている、オープンソースのリバースプロキシです。奥の API には、Python で書いた小さなサーバを2つ使います。
キーの値(demo-key-app01 など)は、この試験のために作った見本の値です。
奥の API を2つ動かす
確かめること:ゲートウェイを通さずに直接呼ぶと、API には「誰が来たか」が分からないこと。
やっていること:ビルの奥に、営業部と経理部にあたる2つの部屋を用意します。
backend.py(奥の API の役。受け取ったヘッダをそのまま返す)
import sys, json
from http.server import BaseHTTPRequestHandler, HTTPServer
name, port = sys.argv[1], int(sys.argv[2])
class H(BaseHTTPRequestHandler):
def do_GET(self):
body = json.dumps({"service": name, "path": self.path,
"client": self.headers.get("X-Client-ID"),
"request_id": self.headers.get("X-Request-ID"),
"api_key": self.headers.get("X-API-Key")}) + "\n"
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(body.encode())
def log_message(self, *args):
pass
HTTPServer(("127.0.0.1", port), H).serve_forever()
注文 API(9001番)と商品 API(9002番)を動かす
python3 backend.py orders 9001 & python3 backend.py products 9002 &
注文 API を直接呼ぶ
curl -s http://127.0.0.1:9001/list
{"service": "orders", "path": "/list", "client": null, "request_id": null, "api_key": null}
結果の読み方:client・request_id・api_key がすべて null(何も届いていない)です。直接呼ばれると、奥の API には相手が誰か分かりません。この先、ゲートウェイを通すと、ここがどう変わるかを見ていきます。
ゲートウェイの設定を書いて動かす(図8の①②)
確かめること:振り分けとルールが、設定ファイルにそのまま書けること。
やっていること:受付のルールブックを書いて、受付を開けます。
gateway.conf(ゲートウェイの設定)
worker_processes 1;
error_log logs/error.log;
pid logs/nginx.pid;
events {}
http {
log_format gw '$time_iso8601 $request_id client=$client_id "$request" '
'$status upstream=$upstream_addr rt=$request_time';
access_log logs/access.log gw;
map $http_x_api_key $client_id {
default "";
"demo-key-app01" "app01";
"demo-key-app02" "app02";
}
limit_req_zone $client_id zone=perclient:1m rate=1r/s;
limit_req_status 429;
server {
listen 127.0.0.1:8080;
default_type application/json;
error_page 429 = @too_many;
error_page 502 = @bad_gateway;
location /orders/ {
if ($client_id = "") {
return 401 '{"error":"invalid or missing API key"}\n';
}
limit_req zone=perclient burst=2 nodelay;
proxy_set_header X-API-Key "";
proxy_set_header X-Client-ID $client_id;
proxy_set_header X-Request-ID $request_id;
proxy_pass http://127.0.0.1:9001/;
}
location /products/ {
if ($client_id = "") {
return 401 '{"error":"invalid or missing API key"}\n';
}
limit_req zone=perclient burst=2 nodelay;
proxy_set_header X-API-Key "";
proxy_set_header X-Client-ID $client_id;
proxy_set_header X-Request-ID $request_id;
proxy_pass http://127.0.0.1:9002/;
}
location / {
return 404 '{"error":"no such API"}\n';
}
location @too_many {
return 429 '{"error":"too many requests"}\n';
}
location @bad_gateway {
return 502 '{"error":"backend unavailable"}\n';
}
}
}
上から順に、かみ砕くとこうなります。
log_formatとaccess_log:記録の形と、記録する場所を決めるmap:X-API-Key ヘッダの値から、誰か(app01・app02)を決める。一覧にないキーは空にするlimit_req_zone:「誰か」ごとに、平均1秒1回までと決める。nginx のドキュメントによると、キーが空のリクエストは数えないlimit_req_status 429:回数を超えたときの番号を 429 にする(nginx の初期値は 503)location /orders/:/orders/ で始まるパスの行き先を決める。誰か分からなければ 401 で断るlimit_req ... burst=2 nodelay:1秒1回に加えて、2回までの連続はその場で通すproxy_set_header:キーのヘッダは空にして外し、誰か(X-Client-ID)と受付番号(X-Request-ID)を付けるproxy_pass:奥の API に渡す。最後に/があるので、/orders/ の部分を外して渡すlocation /:登録のないパスは 404 で断る
設定の書き方が正しいか確かめる
nginx -t -p /srv/gw/ -c gateway.conf
nginx: the configuration file /srv/gw/gateway.conf syntax is ok nginx: configuration file /srv/gw/gateway.conf test is successful
ゲートウェイを動かす(8080番で待ち受ける)
nginx -p /srv/gw/ -c gateway.conf
結果の読み方:「syntax is ok」「test is successful」は、書き方に誤りがないという意味です。受付が開きました。
パスで振り分ける(図9の⑦〜⑯)
確かめること:入口は1つでも、パスによって行き先が分かれること。奥にはキーではなく「誰か」が届くこと。
やっていること:入館証(キー)を見せて、受付に営業部と経理部へ案内してもらいます。
ゲートウェイの /orders/ を呼ぶ
curl -s -H "X-API-Key: demo-key-app01" http://127.0.0.1:8080/orders/list
{"service": "orders", "path": "/list", "client": "app01", "request_id": "e4bf6bc8112bda6b007ef9db0cfe743c", "api_key": null}
ゲートウェイの /products/ を呼ぶ
curl -s -H "X-API-Key: demo-key-app01" http://127.0.0.1:8080/products/list
{"service": "products", "path": "/list", "client": "app01", "request_id": "29f7a6f1a2c9826d7006fb0713c6fb5b", "api_key": null}
結果の読み方:
- service:同じ 8080番の入口なのに、/orders/ は注文 API(orders)、/products/ は商品 API(products)に届いた
- path:奥には
/listと届いた。/orders/ の部分はゲートウェイが外している - client:STEP 1 では null だったところに、
app01が入った。ゲートウェイが付けた - request_id:32桁の受付番号。リクエストごとに違う番号になる(nginx の
$request_idは、16バイトのでたらめな値を16進数で表したもの) - api_key:
null。キーはゲートウェイで外したので、奥には届いていない
キーがなければ入口で断る(図10の❶❷)
確かめること:キーがない・違うリクエストは、奥の API に届く前に断られること。
やっていること:入館証を持たずに来た人、偽の入館証を持ってきた人を試します。
キーを付けずに呼ぶ(最後の行は返ってきた番号)
curl -s -w "%{http_code}\n" http://127.0.0.1:8080/orders/list
{"error":"invalid or missing API key"}
401
一覧にないキーで呼ぶ
curl -s -w "%{http_code}\n" -H "X-API-Key: wrong-key" http://127.0.0.1:8080/orders/list
{"error":"invalid or missing API key"}
401
結果の読み方:どちらも 401 と「キーがない、または正しくない」というメッセージで断られました。奥の注文 API は、このリクエストを受け取っていません。奥の API の側に、キーを確かめる仕組みを1行も書かなくても守れる、ということです。
使いすぎを入口で止める(図10の❸❹)
確かめること:回数は「誰か」ごとに数えられ、使いすぎた利用者だけが止められること。
やっていること:app01 が続けて5回呼び、その直後に app02 が1回呼びます。
app01 で5回続けて呼び、すぐに app02 で1回呼ぶ
sleep 3
for i in 1 2 3 4 5; do
curl -s -o /dev/null -w "%{http_code} " -H "X-API-Key: demo-key-app01" http://127.0.0.1:8080/orders/list
done; echo
curl -s -o /dev/null -w "%{http_code}\n" -H "X-API-Key: demo-key-app02" http://127.0.0.1:8080/orders/list
200 200 200 429 429 200
結果の読み方:
- app01 は、1〜3回目が 200(成功)、4・5回目が 429(多すぎる)でした。1秒1回のペースに加えて2回までの連続を許す設定なので、4回目から止まりました。
- 同じ時に呼んだ app02 は 200 でした。回数は「誰か」ごとに数えているので、app01 の使いすぎが app02 に影響しません。
回数制限のくわしいしくみ(何を単位に数えるか、どう待たせるかなど)は、次の記事で扱います。
記録を入口の1か所で見る(図9の⑮)
確かめること:すべての API の出入りが、ゲートウェイの記録に同じ形で残ること。
やっていること:受付の記録簿を開いて見ます。
ゲートウェイのアクセスログの最後の7行を見る
tail -n 7 logs/access.log
2026-11-02T14:50:12+00:00 6718645086c5b376fe2acbddd73d77be client=app01 "GET /orders/list HTTP/1.1" 200 upstream=127.0.0.1:9001 rt=0.001 2026-11-02T14:50:12+00:00 155f54b6460cdd4d9e1ca746cf699a3b client=app01 "GET /orders/list HTTP/1.1" 200 upstream=127.0.0.1:9001 rt=0.001 2026-11-02T14:50:12+00:00 8116ff22bd7f45169a1861eb58b6bfde client=app01 "GET /orders/list HTTP/1.1" 200 upstream=127.0.0.1:9001 rt=0.001 2026-11-02T14:50:12+00:00 253da7c9e2a0a72348c63ffcd5c3647d client=app01 "GET /orders/list HTTP/1.1" 429 upstream=- rt=0.000 2026-11-02T14:50:12+00:00 27b50cd37a6749b1620fc14b1675f9e6 client=app01 "GET /orders/list HTTP/1.1" 429 upstream=- rt=0.000 2026-11-02T14:50:12+00:00 f9cb270ce1a69f7fd96ff6b30891b67e client=app02 "GET /orders/list HTTP/1.1" 200 upstream=127.0.0.1:9001 rt=0.000 2026-11-02T14:50:12+00:00 26ea232531a98b15603d532abc1308f7 client=app02 "GET /users/list HTTP/1.1" 404 upstream=- rt=0.000
結果の読み方:1行が1回のリクエストです。左から、時刻、受付番号、誰(client=)、リクエスト、結果の番号、渡した先(upstream=)、かかった時間(rt=)です。
- 200 の行は
upstream=127.0.0.1:9001(注文 API に渡した) - 429 や 404 の行は
upstream=-(奥に渡さず、入口で断った)
注文 API の記録も商品 API の記録も、ここ1か所に同じ形で並びます。受付番号は奥の API にも渡しているので、奥の API のログと突き合わせて、1つのリクエストを追いかけることもできます。
ここからは Microsoft の場合です
Azure API Management の3つの部品
API Management は、「受付(ゲートウェイ)」「事務所(管理プレーン)」「案内所(開発者ポータル)」の3つでできています。
Azure API Management(APIM)は、Azure の API ゲートウェイを含む、API を管理するためのサービスです。Microsoft のドキュメントによると、次の3つの部品でできています。
- API ゲートウェイ(データプレーン):この記事で見てきた受付です。すべてのリクエストは、まずここに届きます。
- 管理プレーン(コントロールプレーン):API の提供者が設定をする事務所です。API の定義の取り込み、製品へのまとめ、ポリシーの設定、分析ができます。
- 開発者ポータル:API の利用者向けの案内所です。API の説明を読み、試しに呼び、購読してキーをもらい、自分の使用量を見られます。
ゲートウェイには、Azure が動かすマネージドのゲートウェイのほかに、自分の環境(オンプレミスや他社のクラウドの Kubernetes など)でコンテナとして動かすセルフホステッド ゲートウェイもあります。
| APIM の言葉 | 意味 | この記事の試験でいうと |
|---|---|---|
| API・操作 | 公開する API と、その中の1つ1つの呼び出し | 注文 API の /list |
| 製品(プロダクト) | API をまとめて利用者に見せる単位。保護された製品は購読キーが要る | ― |
| 購読キー | 利用者に配るキー。既定では Ocp-Apim-Subscription-Key ヘッダで送る | X-API-Key のキー |
| ポリシー | ゲートウェイでの処理を決める設定 | gateway.conf のルール |
購読キーは、ヘッダのほかに subscription-key というクエリパラメータでも送れます(ヘッダがないときだけ見られます)。また Microsoft は、購読キーは既定でバックエンドにもそのまま渡されるので、バックエンドのログなどに残したくない場合は、inbound の最後で set-header ポリシーを使ってキーのヘッダを外すよう案内しています。STEP 3 でキーを外したのと同じ考え方です。
ポリシー:受付のルールブック
あらすじ:ポリシーは、リクエストが「入ってきたとき」「奥に渡す前」「戻ってきたとき」「エラーのとき」の4か所に書く、受付のルールです。
ポリシーの骨組み(Microsoft Learn より)
<policies> <inbound> <!-- statements to be applied to the request go here --> </inbound> <backend> <!-- statements to be applied before the request is forwarded to the backend service go here --> </backend> <outbound> <!-- statements to be applied to the response go here --> </outbound> <on-error> <!-- statements to be applied if there's an error condition go here --> </on-error> </policies>
| 場所 | いつ動くか | この記事の試験でいうと |
|---|---|---|
| inbound | リクエストが入ってきたとき | キーの確認・回数制限・ヘッダの付け外し |
| backend | バックエンドに渡す前 | proxy_pass の前後 |
| outbound | レスポンスが戻ってきたとき | (今回は使っていない) |
| on-error | どこかでエラーが起きたとき。残りの処理は飛ばされる | error_page(429・502 の返し方) |
ポリシーは、全体(すべての API)・ワークスペース・製品・API・操作の単位で設定できます。広い単位のポリシーを引き継ぐには、各セクションに <base /> を書きます。Microsoft は、引き継ぎ忘れを防ぐために、各セクションの最初に <base /> を入れることを勧めています。
JWT を確かめるポリシーの例(Microsoft Learn より)
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid."> <openid-config url="https://login.microsoftonline.com/{aad-tenant}/v2.0/.well-known/openid-configuration" /> <audiences> <audience>{audience-value - (ex:api://guid)}</audience> </audiences> <issuers> <issuer>{issuer-value - (ex: https://sts.windows.net/{tenant id}/)}</issuer> </issuers> <required-claims> <claim name="aud"> <value>{backend-app-client-id}</value> </claim> </required-claims> </validate-jwt>
Entra ID が出したアクセストークンを、ゲートウェイで確かめる例です。openid-config で署名の鍵を取り寄せる場所を、audiences で宛先を指定し、合わなければ 401 で断ります。JWT の検証の記事で見た確認を、ゲートウェイが代わりに行うわけです。Entra ID のトークンには、専用の validate-azure-ad-token ポリシーも用意されています。
回数制限のポリシーの例:購読ごとに15秒で3回まで(Microsoft Learn より)
<rate-limit-by-key calls="3" renewal-period="15" counter-key="@(context.Subscription.Id)" />
回数を超えたときのレスポンスの例(Microsoft Learn より)
HTTP/1.1 429 Too Many Requests content-type: application/json retry-after: 60 { "statusCode": 429, "message": "Rate limit is exceeded. Try again in 60 seconds." }
counter-key に何を入れるかで、「誰ごとに数えるか」が決まります。STEP 5 で、nginx の limit_req_zone に $client_id を入れたのと同じです。retry-after ヘッダは、「何秒後にまた試せばよいか」を伝えます。なお、rate-limit-by-key ポリシーは Consumption のプランでは使えません。また Microsoft は、ポリシーで断られたリクエストも含めて、ゲートウェイに届いたすべてのリクエストが回数制限や割り当て量に数えられる、と注意しています。
よくある間違い
| 間違い | どうするか |
|---|---|
| ゲートウェイを置いたのに、奥の API にも外から直接届く | ネットワークで、ゲートウェイからの通信だけを受け付ける |
| キーやトークンを、そのまま奥に渡してログに残る | 確かめ終わったら外し、「誰か」だけを渡す |
| ゲートウェイがあるので、奥の API では何も確かめない | 入口は1枚目の壁。奥でも、その相手に何を許すかは確かめる |
| 回数を IP アドレスだけで数える | 同じ IP の裏に何人もいることがある。キーや利用者ごとに数える |
| ゲートウェイが1台だけ | 入口が止まると全部の API が止まる。複数台・複数のゾーンを考える |
| API を足したのに、振り分けの表を直し忘れる | 設定をコードで管理し、API の追加と一緒に見直す |
回数を IP アドレスだけで数える点については、Microsoft のドキュメントも、NAT の裏では何人もの利用者が1つの公開 IP アドレスを共有していることが多い、と注意しています。
うまくいかないとき
ゲートウェイを通した API がうまくいかないときは、まず返ってきた番号で、「入口で止まったか、奥で止まったか」を分けます。
テスト用の環境で、登録のないパスと、止まっている奥の API を試しました。
登録のないパス(/users/)を呼ぶ
curl -s -w "%{http_code}\n" -H "X-API-Key: demo-key-app02" http://127.0.0.1:8080/users/list
{"error":"no such API"}
404
商品 API(9002番)を止めてから、/products/ を呼ぶ
sleep 3
fuser -s -k 9002/tcp
curl -s -w "%{http_code}\n" -H "X-API-Key: demo-key-app01" http://127.0.0.1:8080/products/list
{"error":"backend unavailable"}
502
ゲートウェイのエラーログを見る
tail -n 1 logs/error.log
2026/11/02 14:50:15 [error] 586#586: *18 connect() failed (111: Connection refused) while connecting to upstream, client: 127.0.0.1, server: , request: "GET /products/list HTTP/1.1", upstream: "http://127.0.0.1:9002/list", host: "127.0.0.1:8080"
結果の読み方:404 は、振り分けの表に /users/ がないので入口で断った、という意味です。502 は、入口は通ったけれど、奥の商品 API につながらなかった、という意味です。エラーログには、9002番への接続が断られた(Connection refused)ことが残っていて、原因が奥にあると分かります。
| 番号 | よくある理由 | 確認すること |
|---|---|---|
| 401 | キーやトークンがない・違う | ヘッダの名前(APIM なら Ocp-Apim-Subscription-Key)と値。トークンの期限や宛先 |
| 404 | 振り分けに登録のないパス | URL のつづり、API や操作の登録 |
| 429 | 回数の上限を超えた | retry-after を待つ。回数を数える単位と上限の設定 |
| 502 | 奥の API につながらない | 奥の API が動いているか。ゲートウェイから奥へのネットワーク |
| 504 | 奥の API の返事が遅すぎる | 奥の API の処理時間と、ゲートウェイの待ち時間の設定 |
| 500 など | 奥の API の中のエラー | 受付番号を手がかりに、奥の API のログを見る |
504 は、ゲートウェイやプロキシが、奥のサーバから時間内に返事をもらえなかったことを表す番号です(RFC 9110)。APIM には、ゲートウェイそのものが動いているかを確かめる /status-0123456789abcdef というパスもあります(Consumption を除く)。これは奥の API ではなく、ゲートウェイだけの状態を確かめるものです。
まとめ
| 項目 | 内容 | 受付でたとえると |
|---|---|---|
| API ゲートウェイ | API の入口を1つにまとめ、振り分けと共通の確認をする | ビルの総合受付 |
| 主な役割 | 振り分け・キーやトークンの確認・回数制限・変換・記録 | 案内・入館証の確認・混雑整理・記録簿 |
| キーの扱い | 入口で確かめたら外し、奥には「誰か」だけを渡す | 部署には「誰が来たか」だけ伝える |
| 断るときの番号 | 401・404・429 は入口、502・504 は奥 | 受付で断るか、部署でつまずくか |
| Azure | API Management(ゲートウェイ・管理プレーン・開発者ポータル)とポリシー | 受付・事務所・案内所とルールブック |
| 注意 | 裏口をふさぐ。奥でも権限を確かめる。入口を止めない | 裏口に鍵をかける |
参考にした資料
この記事は、次の標準と公式ドキュメントで内容を確かめて書きました。仕様や対応状況は変わることがあるので、最新の情報はリンク先で確かめてください。
- RFC 6585: Additional HTTP Status Codes(IETF):429 Too Many Requests の意味と Retry-After
- 502 Bad Gateway・504 Gateway Timeout(MDN):RFC 9110 での 502 と 504 の意味
- Module ngx_http_limit_req_module・Module ngx_http_proxy_module・Module ngx_http_core_module(nginx):回数制限のしくみ・空のキーは数えないこと・limit_req_status の初期値、proxy_pass でのパスの置き換え・空のヘッダを渡さないこと、$request_id
- Use API gateways in microservices(Microsoft Learn):API ゲートウェイの定義、ゲートウェイがない場合の困りごと、ルーティング・アグリゲーション・オフロードの3つのパターン、肩代わりできる仕事、実装の選択肢
- What is Azure API Management?・API gateway in Azure API Management(Microsoft Learn):3つの部品、ゲートウェイの6つの役割、製品とポリシー、マネージドとセルフホステッドのゲートウェイ、断られたリクエストも回数に数えること、ゲートウェイの状態を確かめるパス
- Policies in Azure API Management(Microsoft Learn):inbound・backend・outbound・on-error、適用する単位、base 要素
- Subscriptions in Azure API Management(Microsoft Learn):Ocp-Apim-Subscription-Key と subscription-key、キーが既定でバックエンドに渡ること
- Protect an API in Azure API Management using OAuth 2.0 authorization with Microsoft Entra ID・Tutorial: Transform and protect your API・Advanced request throttling with Azure API Management(Microsoft Learn):validate-jwt の例、rate-limit-by-key の例と Consumption での制限、IP アドレスで数えるときの注意
- How to implement rate limiting in Azure API Management(Microsoft Learn):回数を超えたときの 429 と retry-after の例
あとがき
nginx で小さなゲートウェイを作ってみると、STEP 1 では空っぽだった client の欄に、ゲートウェイを通すだけで app01 が入り、キーが消えるのが印象的でした。入口で確かめて、奥には結果だけを渡す、という役割分担が、手を動かすとよく分かります。一方で、入口に仕事が集まるぶん、入口が止まったときの影響も大きくなります。次の記事では、STEP 5 で少しだけ触れた回数制限(レート制限)を、くわしく見ていきます。
コメント