APIゲートウェイの「交通整理」:パスベースルーティングで設計する堅牢なマイクロサービス基盤
ネットワークエンジニアとして長年現場を渡り歩いていると、システムの「入り口」がいかに重要かを痛感する。マイクロサービスアーキテクチャにおいて、APIゲートウェイは単なるリバースプロキシではない。それは、クライアントという「不特定多数の訪問者」を、適切なサービスという「適切な部屋」へと案内する、熟練のコンシェルジュだ。
今回は、REST APIの原則を守りつつ、APIゲートウェイでいかに美しく、そして運用しやすいパスベースルーティングを設計するか。現場の泥臭い知見を交えて解説しよう。
—
1. なぜ「パスベース」が選ばれるのか
APIゲートウェイでのルーティング戦略には、主に「ホスト名ベース」と「パスベース」がある。
- ホスト名ベース (
api-users.example.comなど): サービスごとにドメインを分けるため、分離は綺麗だが、CORS(Cross-Origin Resource Sharing)の設定やSSL証明書の管理運用コストが肥大化する。 - パスベース (
example.com/api/v1/usersなど): 単一のドメインで運用できるため、管理コストが低い。
実務的には、単一ドメインで統合管理しつつ、パスのプレフィックスでバックエンドを振り分けるパスベースルーティングが、特に中小〜中規模のマイクロサービス環境では最も現実的だ。
2. 美しいエンドポイント設計の鉄則
RESTの原則に従うなら、URLは「リソース」を指し示すべきだ。APIゲートウェイの設計において、ルーティングのキーとなるパスは、バックエンドのコンテキストと一致させることが鉄則となる。
例えば、以下の設計は「美しい」といえる。
GET /api/v1/users→User Serviceへ転送GET /api/v1/orders→Order Serviceへ転送
ここで重要なのは、「ゲートウェイを通すパス」と「サービス内部のパス」をどうマッピングするかという点だ。
—
3. Nginxを例にしたルーティングの実装
多くの現場で標準的に使われる Nginx を例に、APIゲートウェイの挙動を見てみよう。設定ファイルでのポイントは location ブロックの優先順位と proxy_pass の書き方だ。
# APIゲートウェイの設定例
upstream user_service {
server user-svc.internal:8080;
}
server {
listen 80;
server_name api.example.com;
# /api/v1/users へのリクエストを User Service へ転送
location /api/v1/users {
# 末尾の / に注意。パスを書き換える場合は調整が必要
proxy_pass http://user_service;
# クライアントの元のIPをヘッダーに含める(ログ解析で必須)
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
}
}
ここで多くの若手がハマるのが、proxy_pass の末尾に / をつけるか否かの挙動だ。
proxy_pass http://user_service;と書いた場合、リクエストされたパス全体がそのままバックエンドに送られる。proxy_pass http://user_service/;と書くと、/api/v1/usersというプレフィックスが削除され、バックエンドには/として届く。
この挙動を理解していないと、バックエンド側で「404 Not Found」が頻発する原因になる。
—
4. トラブルシューティングの現場知見:HTTPヘッダーの継承
APIゲートウェイを導入すると、パケットは「クライアント → ゲートウェイ → サービス」と2回飛ぶことになる。ここで注意すべきなのが Host ヘッダーや X-Forwarded-For ヘッダーの扱いだ。
クライアントが送ったリクエストを curl でデバッグする際は、必ずゲートウェイを介した後のヘッダーを確認してほしい。
# ゲートウェイ経由でヘッダーを確認
curl -I -H "X-Custom-Trace-ID: 12345" https://api.example.com/api/v1/users
バックエンド側のログに、元のクライアントのIPアドレスが残っていないというトラブルは、インフラエンジニアの「あるある」だ。必ず proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; を設定し、バックエンド側でこのヘッダーを解釈できるようにしておくこと。
—
5. Pythonによる疎通確認スクリプト
最後に、APIゲートウェイが正しくルーティングしているか、簡単なスクリプトでテストする習慣をつけよう。
import requests
# ゲートウェイのURL
BASE_URL = "https://api.example.com"
def test_routing(path):
try:
response = requests.get(f"{BASE_URL}{path}")
print(f"Path: {path} | Status: {response.status_code}")
# どのサービスが応答したかをヘッダーで識別できるようにしておくと便利
print(f"Response Header: {response.headers.get('X-Served-By')}")
except Exception as e:
print(f"Error: {e}")
# 複数のサービスへのルーティングをまとめてテスト
endpoints = ["/api/v1/users", "/api/v1/orders"]
for ep in endpoints:
test_routing(ep)
最後に:エンジニアとしての心構え
APIゲートウェイのルーティングは、一度構築すれば終わりではない。サービスが増えるたびに location ブロックは肥大化し、依存関係は複雑になる。
だからこそ、「シンプルに保つこと」を常に意識してほしい。パスの設計が複雑になりすぎていると感じたら、それはマイクロサービスの境界線が曖昧になっているサインかもしれない。技術は常に「誰が運用するのか」という視点に立ち返ることで、初めて長く愛されるシステムになる。
さあ、次は君たちの手で、美しいルーティングを設計してほしい。現場からは以上だ。
コメント