【図解】APIゲートウェイとは?APIの入口をまとめて守るしくみと役割を初心者向けに解説

ここまでのシリーズでは、API を呼ぶ人やプログラムが「誰か」を示すしくみを見てきました。API キー、トークン、証明書、そしてワークロード ID です。でも、API が10個、20個と増えると、それぞれの API で同じ確認を作るのは大変です。

そこで出てくるのが、API の入口を1つにまとめる「API ゲートウェイ」です。この記事では、ビルの総合受付のたとえを使いながら、Microsoft のドキュメントで確かめ、テスト用の環境で nginx を API ゲートウェイとして実際に動かした結果と一緒に、一歩ずつ図にしました。

この記事でわかること
  1. API ゲートウェイとは何か、なぜ入口を1つにまとめるのか
  2. ゲートウェイの役割(振り分け・確認・回数制限・記録など)と、似た機器との違い
  3. リクエストがゲートウェイを通る流れと、断るときの番号(401・404・429・502)
  4. nginx で、振り分け・キーの確認・回数制限・記録を試す方法
  5. Azure API Management の部品とポリシーの考え方

先に覚えておく3つの言葉

最初に、いちばん大事な3つの言葉を、ビルの受付にたとえて押さえておきます。

API ゲートウェイたとえ:ビルの総合受付API の入口を1つにまとめ、確認と案内をする係バックエンドたとえ:奥にある各部署実際に仕事をする API。外から直接は見えないポリシーたとえ:受付のルールブック入口で何を確かめ、どう案内するかの決まりこの3つが分かれば、この記事の話はほぼ追える
図1 先に覚えておく3つの言葉

ほかにも、この記事にはいくつか専門の言葉が出てきます。先に、ざっくりした意味を並べておきます。読んでいて迷ったら、ここに戻ってきてください。

言葉ざっくりした意味受付でたとえると
リバースプロキシリクエストを代わりに受け取って、奥のサーバに渡すしくみ取り次ぎ係
ルーティングパス(URL の後ろの部分)を見て、行き先を決めること行き先の案内
オフロード各 API の共通の仕事を、入口が肩代わりすること入館証の確認を受付だけでする
回数制限決まった時間に呼べる回数を制限すること(レート制限)混んだら待ってもらう
ステータスコード結果を表す3桁の番号。200 は成功、401・404・429・502 などは失敗受付の返事

この記事の地図

ひとことで言うと

外から来るリクエストは、すべて API ゲートウェイを通ってから、奥の API に届きます。

先に全体の地図を見ておくと、迷いにくくなります。

外(インターネット・社内のアプリ)スマホアプリ取引先のシステム社内のバッチAPI ゲートウェイ① 行き先を決める② 誰かを確かめる③ 回数を見張る④ 記録を残す中(バックエンド)注文 API商品 API会員 API外からの入口は1つ。確認や記録は入口でまとめて行い、奥の API は仕事に集中する
図2 この記事の地図

左がAPI を呼ぶ側(スマホアプリ、取引先のシステム、社内のバッチなど)、右が実際に仕事をする API(バックエンド)です。真ん中のゲートウェイが、行き先を決め、誰かを確かめ、回数を見張り、記録を残します。奥の API は、自分の仕事だけに集中できます。

まずはたとえで:ビルの総合受付

ひとことで言うと

API ゲートウェイは、API の世界の「総合受付」です。

大きなビルを思い浮かべてください。受付がないビルでは、来客は営業部や経理部の場所を自分で覚えておく必要があります。各部署は、それぞれ自分で入館証を確かめ、誰が来たかを記録します。部署ごとに確認のしかたも記録の形もばらばらです。

受付がないビル営業部経理部開発部来客は部署の場所を全部覚える各部署がそれぞれ入館証を確かめる誰が来たかの記録がばらばら総合受付があるビル総合受付(ゲートウェイ)営業部経理部開発部来客は受付だけを知っていればよい入館証の確認・記録は受付でまとめて混んだら受付で待ってもらうAPI ゲートウェイは、API の世界の「総合受付」
図3 たとえで見る API ゲートウェイ

総合受付があるビルでは、来客は受付だけを知っていれば足ります。受付が入館証を確かめ、行き先を案内し、記録を残します。混んでいるときは、受付で少し待ってもらいます。各部署は、自分の仕事に集中できます。API ゲートウェイは、この総合受付の役目を、API の世界でするものです。

直接つなぐか、ゲートウェイを通すか

ひとことで言うと

API が増えるほど、入口をまとめる効果が大きくなります。

大事な比較なので、先に並べておきます。

直接つなぐアプリ注文 API認証・記録も自前商品 API認証・記録も自前会員 API認証・記録も自前アプリは入口を3つ知る必要がある認証・回数制限・記録を3回作るゲートウェイを通すアプリゲートウェイ注文 API商品 API会員 APIアプリは入口を1つだけ知ればよい共通の確認はゲートウェイで1回API が増えるほど、入口をまとめる効果が大きくなる
図4 直接つなぐ場合とゲートウェイを通す場合

Microsoft の設計ガイド(Azure Architecture Center)は、API ゲートウェイを「クライアントとアプリケーションのサービスのやり取りを1か所で管理する入口」と説明しています。そして、ゲートウェイがない場合の困りごとを挙げています。かみ砕くと、次のとおりです。

困りごとどういうことか受付でたとえると
呼ぶ側が複雑になるアプリが API の場所を全部覚え、失敗にもそれぞれ備える来客が部署の場所を全部覚える
結びつきが強くなるAPI の作りを変えると、呼ぶ側も直す必要がある部署が引っ越すと、来客に知らせ直す
往復が増える1つの操作で、いくつもの API を呼ぶ書類をもらうのに部署を何か所も回る
同じ仕事を何度も作る認証・TLS・回数制限を API ごとに作る部署ごとに入館証を確かめる
攻撃される入口が増える外に見える入口の数だけ、守る場所が増える出入口がたくさんあるビル

ゲートウェイの役割

ひとことで言うと

ゲートウェイの仕事は、「振り分け」と「どの API にも共通する確認」の2つです。

行き先を決めるパスで振り分ける(ルーティング)誰かを確かめるAPI キー・JWT・証明書回数を見張る回数制限・割り当て量中身を整えるヘッダの追加・削除・変換記録するログ・メトリクス・追跡その他TLS の終端・キャッシュ・圧縮どの API にも共通する仕事を、入口でまとめて引き受ける(オフロード)ゲートウェイの仕事は「振り分け」と「共通の確認」
図5 API ゲートウェイの主な役割

Microsoft のドキュメントは、Azure API Management のゲートウェイがすることとして、次の6つを挙げています。ほかのゲートウェイ製品でも、だいたい同じです。

  1. API の呼び出しを受け取って、ふさわしいバックエンドに振り分ける
  2. API キーや、JWT・証明書などの資格情報を確かめる
  3. 使用量の上限(割り当て量)や回数制限を守らせる
  4. 必要に応じて、リクエストやレスポンスを変換する
  5. 設定すれば、レスポンスをキャッシュ(取っておいて使い回すこと)する
  6. 監視や調査のために、ログ・メトリクス・追跡の情報を出す

Microsoft の設計ガイドは、ゲートウェイに肩代わりさせられる仕事の例として、TLS の終端、mTLS、認証、IP アドレスの許可・拒否、回数制限、ログと監視、レスポンスのキャッシュ、WAF、圧縮などを挙げています。TLS や mTLS、API キーや JWT の検証など、このシリーズで見てきたものの多くを、入口でまとめて引き受けられるということです。

似た機器との違い

ひとことで言うと

似た機器とは、「何が主役か」で見分けます。API ゲートウェイの主役は「API の管理」です。

リバースプロキシ受け取って奥に渡すゲートウェイの土台ロードバランサ同じ API の何台かに分ける負荷の分散が主役WAF攻撃らしい通信を止める中身の危険を見るAPI ゲートウェイAPI ごとに確認・制限・記録API の管理が主役実際の製品は、いくつかの役割を兼ねることが多い。組み合わせて置くこともある似た機器と「何が主役か」で見分ける
図6 似た機器との違い
機器主な仕事受付でたとえると
リバースプロキシリクエストを代わりに受け取り、奥に渡す。ゲートウェイの土台になる取り次ぎ係
ロードバランサ同じ仕事をする何台かのサーバに、負荷を分ける同じ窓口を何か所か開けて、空いているほうへ案内する
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管理者入口の URLゲートウェイだけAPI キー・トークン自分の身分振り分けの表パス → どの API かルール(ポリシー)確認・制限・変換照合用の情報キーの一覧・公開鍵仕事の中身注文・商品などゲートウェイからだけ外から直接は来ない振り分け・ルールの設定API を足すたびに更新キーの発行・止める利用者ごと利用者が知るのは入口だけ。奥の API の場所は、ゲートウェイだけが知っている
図7 誰が何を持つか

受付でたとえると、来客が持っているのは「ビルの住所」と「入館証」だけです。各部署が何階にあるかは、受付の案内表にだけ書いてあります。部署の側は、受付を通った人だけを迎えます。裏口から勝手に入られないように、ネットワークの設定でゲートウェイ以外からの通信を受け付けないようにしておくことも大事です。

全体の流れ

ここからは、注文 API と商品 API の前にゲートウェイを置く例で、流れを順に見ます。準備、使うとき、断るときの3つです。

準備:振り分けとルールを登録する

あらすじ:管理者が、ゲートウェイに「振り分けの表」と「ルール」を登録し、利用者には「入口の URL」と「キー」だけを渡します。

管理者APIゲートウェイバックエンドAPI利用者のアプリ① 振り分けを登録/orders/ → 注文 API② ルールを登録キーの確認・回数制限・記録③ ゲートウェイからだけ受けるネットワークで絞る④ API キーを発行して渡す利用者ごと⑤ 入口の URL を伝えるゲートウェイの URL だけ⑥ アプリにURL とキー利用者に渡すのは「入口」と「キー」だけ。奥の API の場所は渡さない
図8 準備の流れ(①〜⑥)
手順誰が・どこで何をするか物(設定・キー)はどうなるか
①管理者・ゲートウェイで操作振り分けを登録する「/orders/ は注文 API へ」という表ができる
②管理者・ゲートウェイで操作ルールを登録するキーの確認・回数制限・記録が決まる
③管理者・バックエンドで操作ゲートウェイからだけ受け付ける裏口をふさぐ
④管理者 → 利用者API キーを発行して渡す利用者ごとに別のキー
⑤管理者 → 利用者入口の URL を伝えるゲートウェイの URL だけ。奥の場所は伝えない
⑥利用者アプリに URL とキーを設定するキーはシークレットとして扱う

使うとき:入口で確かめてから、奥に渡す

あらすじ:リクエストはまずゲートウェイに届きます。ゲートウェイが行き先・誰か・回数を確かめ、ヘッダを整えてから、奥の API に渡します。

利用者のアプリAPIゲートウェイバックエンド(注文 API)⑦ GET /orders/listX-API-Key を付ける⑧ 行き先を決める/orders/ → 注文 API⑨ 誰かを確かめるキー → app01⑩ 回数を確かめるapp01 はまだ大丈夫⑪ ヘッダを整えるキーを外し、app01 と受付番号を付ける⑫ GET /listX-Client-ID: app01⑬ 仕事をするapp01 として⑭ レスポンス⑮ 記録する誰・どこ・結果・時間⑯ レスポンス共通の確認は⑧〜⑪でゲートウェイが行い、バックエンドは⑬の仕事だけをする
図9 使うときの流れ(⑦〜⑯)
手順誰が・どこで何をするか物(キー・ヘッダ)はどうなるか
⑦アプリ → ゲートウェイキーを付けてリクエストを送るキーは X-API-Key ヘッダに入る
⑧ゲートウェイパスから行き先を決める/orders/ なら注文 API
⑨ゲートウェイキーから誰かを確かめる一覧と照らして app01 と分かる
⑩ゲートウェイ回数を確かめるapp01 の回数を数える
⑪ゲートウェイヘッダを整えるキーは外し、「app01」と受付番号を付ける
⑫ゲートウェイ → 注文 APIリクエストを渡すキーは奥に届かない
⑬注文 API仕事をする「app01 からの依頼」として処理する
⑭注文 API → ゲートウェイレスポンスを返す―
⑮ゲートウェイ記録する誰・どこ・結果・時間がログに残る
⑯ゲートウェイ → アプリレスポンスを返す―

⑪がポイントです。キーは入口で確かめたら役目が終わるので、奥には渡しません。奥に渡るのは「app01 から」という結果だけです。こうすると、奥の API のログなどにキーが残る心配もなくなります。受付で入館証を見たら、部署には「〇〇社の△△さんが来ました」とだけ伝えるのと同じです。

断るとき:入口で止めて、番号で知らせる

あらすじ:確認に通らないリクエストは、ゲートウェイがその場で断り、理由をステータスコード(番号)で返します。

利用者のアプリAPIゲートウェイバックエンド❶ キーなし・違うキー⑨で止める❷ 401❸ 短い間に何度も⑩で止める❹ 429❺ 登録のないパス⑧で止める❻ 404❼ 正しいリクエスト❽ 転送止まっている❾ 502断り方は番号で分かる。401・429・404 はバックエンドまで届かない
図10 ゲートウェイが断るときの流れ(❶〜❾)
番号止まった場所(最初の図)意味受付でたとえると
401⑨ 誰かを確かめるキーがない・違う入館証がない
429⑩ 回数を確かめる短い間に呼びすぎ混んでいるので少し待って
404⑧ 行き先を決める登録のないパスそんな部署はない
502⑫ 奥に渡す奥の API につながらない部署に誰もいない

401・429・404 は、入口で止まるので、奥の API まで届きません。知らない相手や使いすぎの相手のリクエストを、奥の API は見ることさえありません。502 だけは、入口は通ったけれど奥でつまずいた、という意味です。429 は RFC 6585 で決まった番号で、「決まった時間に送るリクエストが多すぎる(レート制限)」ことを表します。502 は RFC 9110 で、ゲートウェイやプロキシが奥のサーバから正しい返事をもらえなかったことを表します。

ゲートウェイの3つの使い方

ひとことで言うと

「振り分ける」「まとめる」「肩代わりする」の3つの使い方があります。

ゲートウェイ ルーティング1つの入口から、パスで各 API へ受付が行き先を案内するゲートウェイ アグリゲーション1回の呼び出しで、裏の複数 API をまとめる受付が各部署から書類を集めて渡すゲートウェイ オフロード認証・TLS・記録などを入口に集める入館証の確認を受付だけでするMicrosoft の設計ガイドが挙げる3つの使い方
図11 API ゲートウェイの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つの部屋を用意します。

curl直接呼ぶ:9001バックエンド(このマシンの中)注文 APIbackend.py orders 9001商品 APIbackend.py products 9002受け取ったヘッダをそのまま返す作りclient・request_id・api_key がどう届いたかが分かるまずは奥の部屋だけを用意する。直接呼ぶと、誰が来たかは分からない
図12 STEP 1 の様子

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(受付のルールブック)map $http_x_api_keyキー → 誰か(app01・app02)⑨limit_req_zone誰かごとに 1秒1回(少しの連続は許す)⑩location /orders/パスで行き先を決める⑧proxy_set_headerキーを外し、誰か・受付番号を付ける⑪access_log誰・どこ・結果・時間を記録⑮return 401 / 404その場で断る❷❻図の①②で登録する「振り分け」と「ルール」を、設定ファイルに書く
図13 STEP 2 の gateway.conf の中身(右の番号は図9の手順)

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つでも、パスによって行き先が分かれること。奥にはキーではなく「誰か」が届くこと。

やっていること:入館証(キー)を見せて、受付に営業部と経理部へ案内してもらいます。

curlキー付きゲートウェイ :8080/orders/ → :9001/products/ → :9002キー → app01バックエンドが受け取ったものpath/list(前の部分が外れる)clientapp01request_id32桁の受付番号api_keynull(届かない)入口は1つでも、パスで行き先が分かれ、奥には「誰か」だけが届く
図14 STEP 3 の様子

ゲートウェイの /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 に届く前に断られること。

やっていること:入館証を持たずに来た人、偽の入館証を持ってきた人を試します。

リクエストゲートウェイの判断結果キーを付けない誰か分からない → 入口で断る401違うキー(wrong-key)一覧にない → 入口で断る401バックエンドは、知らない相手からのリクエストを見ることさえない
図15 STEP 4 の様子

キーを付けずに呼ぶ(最後の行は返ってきた番号)

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回1回目2002回目2003回目2004回目4295回目429同じ時に app021回目2001秒1回のペースに加えて、少しの連続(burst=2)だけ許すので、4回目から断る数えるのは「誰か」ごと。app01 が使いすぎても app02 は困らない使いすぎる利用者だけを、入口で待ってもらう(くわしくは次の記事)
図16 STEP 5 の様子

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 の出入りが、ゲートウェイの記録に同じ形で残ること。

やっていること:受付の記録簿を開いて見ます。

時刻受付番号誰リクエスト結果行き先・時間14:50:126718…app01GET /orders/list200:9001 0.001秒14:50:12253d…app01GET /orders/list429-(送らない)14:50:1226ea…app02GET /users/list404-(送らない)全部の API の出入りが、入口の1か所に同じ形で残る
図17 STEP 6 のアクセスログの読み方

ゲートウェイのアクセスログの最後の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つの部品でできています。

Azure API ManagementAPI ゲートウェイデータプレーン・リクエストを受けて振り分け・キー・JWT・証明書を確かめる・回数制限・変換・キャッシュ・ログ・メトリクスを出す管理プレーンコントロールプレーン・API の定義を取り込む・製品(プロダクト)にまとめる・ポリシーを設定する・分析を見る開発者ポータル利用者向けのサイト・API の説明を読む・試しに呼んでみる・購読してキーをもらう・自分の使用量を見る受付(ゲートウェイ)・事務所(管理プレーン)・案内所(ポータル)の3つ
図18 Azure API Management の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か所に書く、受付のルールです。

利用者のアプリAPI Management(ゲートウェイ)バックエンドAPI❶ リクエスト購読キー・トークン❷ inboundキー・JWT・回数・ヘッダ❸ backend転送の前の処理❹ 転送❺ レスポンス❻ outboundレスポンスを整える❼ レスポンスどこかでエラーが起きると、残りを飛ばして on-error に移るポリシーは全体・製品・API・操作などの単位で設定し、base 要素で上の単位のものを引き継ぐポリシーは「入るとき」「送る前」「戻るとき」「エラーのとき」の4か所に書く
図19 API Management のポリシーの流れ(❶〜❼)

ポリシーの骨組み(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 がうまくいかないときは、まず返ってきた番号で、「入口で止まったか、奥で止まったか」を分けます。

返ってきた番号どこで止まったか401入口:キーやトークンがない・違う404入口:振り分けに登録のないパス429入口:回数の上限を超えた502奥:バックエンドにつながらない504奥:バックエンドの返事が遅すぎる500 など奥:バックエンドの中のエラーまず番号で「入口で止まったか、奥で止まったか」を分け、ゲートウェイのログを見る
図20 ゲートウェイを通した 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 は奥受付で断るか、部署でつまずくか
AzureAPI Management(ゲートウェイ・管理プレーン・開発者ポータル)とポリシー受付・事務所・案内所とルールブック
注意裏口をふさぐ。奥でも権限を確かめる。入口を止めない裏口に鍵をかける

参考にした資料

この記事は、次の標準と公式ドキュメントで内容を確かめて書きました。仕様や対応状況は変わることがあるので、最新の情報はリンク先で確かめてください。

あとがき

nginx で小さなゲートウェイを作ってみると、STEP 1 では空っぽだった client の欄に、ゲートウェイを通すだけで app01 が入り、キーが消えるのが印象的でした。入口で確かめて、奥には結果だけを渡す、という役割分担が、手を動かすとよく分かります。一方で、入口に仕事が集まるぶん、入口が止まったときの影響も大きくなります。次の記事では、STEP 5 で少しだけ触れた回数制限(レート制限)を、くわしく見ていきます。

コメント