PythonでAPIテストを書くとき「requestsとPlaywright API、どちらを使うべきか」と迷うQAエンジニアは多い。requestsはシンプルで学習コストが低く、Playwright APIはE2Eテストとの統合に強い。本記事では15年以上のQA実務経験をもとに、同じAPIテストを両ツールで書き比べながら、使い分けの判断基準を実務目線で解説する。
requestsは「APIテスト専用の軽量ツール」、Playwright APIは「E2E+APIを1つのコードベースで管理するツール」——目的が違うので、どちらが優れているという話ではない。
📌 この記事はこんな人向け
- PythonでAPIテストを始めたいが、どのツールを選ぶか迷っている
- requestsでAPIテストを書いているが、Playwright APIへの移行を検討している
- E2EテストにPlaywrightを使っており、APIテストも統合したい
- 2ツールのコードの書き方の違いを実際に見て比較したい
✅ この記事を読むと得られること
- requestsとPlaywright APIの違いが比較表で整理できる
- 同じAPIテストを両ツールで書いたコードを見て実力差を体感できる
- 「どちらを選ぶべきか」の判断基準とチェックリストが手に入る
👤 この記事を書いた人
QAエンジニア・テスト自動化エンジニアとして15年以上の実務経験あり。requestsはAPIテストの黎明期から、Playwright APIはリリース初期から実務で使用。両ツールを実際のプロジェクトで運用してきた経験をもとに書いている。
⚡ 迷ったらこれで決める
| APIテストのみ | → requests を選ぶ |
| E2EテストもPlaywrightで書いている | → Playwright APIに統合する |
| まず学習コストを抑えたい | → requests から始める |
「APIテストをPythonで書きたい」と思ったとき、最初に候補に挙がるのが requests ライブラリだ。シンプルで学習コストが低く、pytestとの組み合わせは定番中の定番。一方、E2EテストにPlaywrightを使っているチームでは「APIテストもPlaywright APIに統一したい」という声が出てくる。
playwright.request.new_context() で利用する APIRequestContext 機能を指します。Playwright Test(Node.js版)そのものではなく、Python版Playwrightが提供するAPI Testing機能です。本記事では「どちらが優れているか」ではなく、「どんなチーム・運用に向いているか」を実務ベースで整理していく。
📌 この記事の結論
- APIテストのみならrequests + pytestが最もシンプルで合理的
- E2EテストにPlaywrightを使っているなら、APIテストもPlaywright APIに統合する価値が高い
- 2ツールは競合ではなく用途に応じた使い分けが正解
requestsとPlaywright APIとは|基本比較
| 項目 | 📦 requests | 🎭 Playwright API |
|---|---|---|
| 用途 | HTTPリクエスト送信・APIテスト専用 | E2E + APIテストの統合 |
| 学習コスト | ◎ 非常に低い | △ API単体なら導入可能だが、E2E統合まで使うと学習範囲が広がる |
| コード量 | ◎ 少ない・シンプル | ○ やや多め |
| E2Eとの統合 | ✕ できない | ◎ 同一コードで統合可能 |
| CI/CD親和性 | ◎ pytest経由で簡単 | ○ pytest単体でも利用可能。fixtureを活用する場合はpytest-playwrightが便利 |
| ネットワーク傍受・モック | △ responses等で別途対応 | ◎ E2Eテストでは page.route() によるブラウザ通信のモック・傍受を標準機能で実装可能 |
| インストールの重さ | ◎ 軽量(pip一発) | △ 一般的なセットアップではブラウザバイナリのインストールを伴うため環境構築が重め |
| ブラウザ不要 | ◎ 完全不要 | ○ APIテストのみならブラウザ不要で実行可能 |
| 非同期対応 | △ requests自体は同期専用(非同期はhttpx等が必要) | ○ async APIを正式提供(QA現場ではsync採用が比較的多い) |
| 接続再利用・Cookie共有 | ◎ requests.Session() で簡単に実現 | ○ APIRequestContextでCookie・ヘッダー共有可能(実務ではfixture化推奨) |
| Python APIテスト実績 | ◎ pytest + requests構成が非常に多い | △ 増加中 |
httpx を採用するチームも増えている。2026年現在、QA現場では依然として requests + pytest 構成が広く採用されているが、非同期APIテストが必要な場合は httpx + pytest-asyncio も有力な選択肢だ。詳細はFAQを参照してほしい。コードで見る違い|同じAPIテストを書き比べ
同じシナリオ(ユーザー一覧取得・ユーザー作成・認証)を両ツールで書いた場合の違いを見てみよう。
① GETリクエスト・基本的なアサーション
# ✅ requests + pytest
import requests
def test_ユーザー一覧が取得できる():
response = requests.get(
"https://jsonplaceholder.typicode.com/users",
timeout=(3, 10)
)
assert response.status_code == 200
users = response.json()
assert len(users) > 0
assert "name" in users[0]# 🎭 Playwright API + pytest
# ※ playwright fixture を使う場合は pytest-playwright プラグインが必要
from playwright.sync_api import Playwright
def test_ユーザー一覧が取得できる(playwright: Playwright):
api = playwright.request.new_context(
base_url="https://jsonplaceholder.typicode.com"
)
response = api.get(
"/users",
timeout=10_000 # ms指定(10秒)
# Playwrightにはデフォルト30秒タイムアウトあり。実務ではCI安定化のため明示指定が推奨
)
assert response.status == 200
users = response.json()
assert len(users) > 0
assert "name" in users[0]
# サンプルでは簡略化のため直接disposeしているが、実務ではfixture化して共通管理する
api.dispose()requests.get(url) と書くと timeout がデフォルト無制限になる。ネットワーク障害時にCIが数十分ハングするリスクがあるため、実務では必ず timeout=(接続秒, 読み取り秒) を明示しよう。単純なGETなら
requests の方がコードが短くシンプルだ。実務Tipとして、requestsでは response.raise_for_status() を使うことで4xx/5xxを例外化できる。なおPlaywright APIには同等メソッドはないため、通常は assert response.status == 200 のように明示的に検証する。どちらのアプローチも実務では広く使われている。response.json() を直接呼ぶと JSONDecodeError が発生する。本番テストでは Content-Type の確認やエラーログ出力を検討しよう。サンプルコードは簡略化のため省略している。② POSTリクエスト・JSONボディ送信
# ✅ requests + pytest
import requests
def test_投稿が作成できる():
payload = {
"title": "自動テスト投稿",
"body": "Playwright APIとrequestsの比較",
"userId": 1
}
response = requests.post(
"https://jsonplaceholder.typicode.com/posts",
json=payload,
timeout=(3, 10)
)
assert response.status_code == 201
data = response.json()
assert data["title"] == payload["title"]
assert "id" in data# 🎭 Playwright API + pytest
def test_投稿が作成できる(playwright: Playwright):
api = playwright.request.new_context(
base_url="https://jsonplaceholder.typicode.com"
)
payload = {
"title": "自動テスト投稿",
"body": "Playwright APIとrequestsの比較",
"userId": 1
}
response = api.post(
"/posts",
json=payload,
timeout=10_000 # ms指定(10秒)。デフォルト30秒あり、実務では明示指定推奨
)
assert response.status == 201
data = response.json()
assert data["title"] == payload["title"]
assert "id" in data
# サンプルでは簡略化のため直接disposeしているが、実務ではfixture化して共通管理する
api.dispose()requests は
json=payload、Playwright APIも json=payload を使うことで Content-Type が自動的に application/json に設定される。実務では両ツールとも json= パラメータを使うのが安全で推奨だ。③ 認証トークン付きリクエスト
# ✅ requests + pytest(Cookie認証)
import requests
import pytest
BASE_URL = "https://restful-booker.herokuapp.com"
@pytest.fixture(scope="session")
def auth_token() -> str:
response = requests.post(
f"{BASE_URL}/auth",
json={"username": "admin", "password": "password123"},
timeout=(3, 10)
)
response.raise_for_status() # HTTPエラーを即検知
data = response.json()
assert "token" in data, "認証レスポンスにtokenが含まれていない"
return data["token"]
def test_予約が削除できる(auth_token: str):
headers = {"Cookie": f"token={auth_token}"}
response = requests.delete(
f"{BASE_URL}/booking/1",
headers=headers,
timeout=(3, 10)
)
assert response.status_code in (200, 201)# 🎭 Playwright API + pytest(Cookie認証)
import pytest
from playwright.sync_api import Playwright, APIRequestContext
@pytest.fixture(scope="session")
def api_context(playwright: Playwright) -> APIRequestContext:
# 実務ではconftest.pyでfixture化して全テストで使い回す
api = playwright.request.new_context(
base_url="https://restful-booker.herokuapp.com"
)
yield api
api.dispose()
@pytest.fixture(scope="session")
def auth_token(api_context) -> str:
response = api_context.post(
"/auth",
json={"username": "admin", "password": "password123"},
timeout=10_000 # ms指定(10秒)
)
assert response.status == 200
data = response.json()
assert "token" in data, "認証レスポンスにtokenが含まれていない"
return data["token"]
def test_予約が削除できる(api_context, auth_token: str):
response = api_context.delete(
"/booking/1",
headers={"Cookie": f"token={auth_token}"}
)
assert response.status in (200, 201)どちらも
scope="session" で認証トークンを使い回せる。Playwright APIは api_context fixture を session スコープにすることで接続を使い回せるため、大規模テストで効率化しやすい。なお requests.Session() でも同様の接続最適化は可能だ。④ Playwright APIの真骨頂|E2E+APIの統合テスト
これが requestsでは実現できない、Playwright APIの最大の強みだ。
# 🎭 Playwright:E2EテストとAPIテストを1つのテストで統合
from playwright.sync_api import Page, expect
def test_ユーザー登録後にAPIでも確認できる(page: Page, playwright):
# ① UIでユーザーを登録(E2Eテスト)
page.goto("https://example.com/register")
page.fill("#email", "test@example.com")
page.fill("#password", "SecurePass123")
page.click("#register-btn")
expect(page.get_by_text("登録完了")).to_be_visible()
# ② APIでユーザーが作成されたことを確認(APIテスト)
api = playwright.request.new_context(
base_url="https://example.com"
)
response = api.get("/api/users?email=test@example.com")
assert response.status == 200
users = response.json()
assert len(users) == 1
assert users[0]["email"] == "test@example.com"
api.dispose()
# requests単体ではUI操作を扱えないため、
# このようなE2E+API統合はPlaywrightとの組み合わせが自然🔑 これがPlaywright APIの大きな強み
「UIで操作した結果をAPIで検証する」統合テストを、同一fixture・同一コードベースで自然に統合しやすいのがPlaywright APIの強みだ。requestsでもSelenium等と組み合わせれば実現は可能だが、構成が分かれやすくなる。E2EとAPIを一元管理したい場合にPlaywright APIは非常に合理的な選択だ。
Playwrightでは UI要素の待機込みアサーションには
expect(locator) を使い、APIレスポンスの確認には通常の assert を使う構成が実務では一般的だ。expect() はAuto-waitが働くため、要素の表示を待ちながら検証できる。APIの response.status や response.json() には assert で十分だ。requestsの強みと弱み
| ✅ 強み | ⚠️ 弱み |
|---|---|
|
|
Playwright APIの強みと弱み
| ✅ 強み | ⚠️ 弱み |
|---|---|
|
|
どちらを選ぶか|判断フロー
▶ E2EテストにPlaywrightを使っていますか? |
YES ↓ | NO ↓ |
✅ Playwright APIに統合を推奨 | ▶ APIテストのみが対象ですか? |
YES ↓ | NO ↓ |
✅ requestsを推奨 | ⚡ 両方の併用を検討 |
移行判断チェックリスト|requests → Playwright API
現在requestsでAPIテストを書いているチームがPlaywright APIに移行すべきかを判断するチェックリストだ。
| チェック項目 | 点数 |
|---|---|
| E2EテストにPlaywrightをすでに使っている | YES → +3点 |
| 「UIで操作した結果をAPIで検証する」統合テストを書きたい | YES → +3点 |
| ネットワーク傍受・APIモックをテストで使いたい | YES → +2点 |
| テストレポートをE2EとAPIで統一したい(Allure等) | YES → +1点 |
| チームがPlaywrightを習得済み | YES → +1点 |
| APIテストのみで、E2E統合の予定がない | YES → −2点 |
🔑 判断基準
- 4点以上:Playwright APIへの移行を積極的に検討すべき
- 2〜3点:新規テストはPlaywright APIで書き、既存requestsは維持する部分移行を検討
- 1点以下:requests + pytestを継続するのが最も合理的
💡 実務でよく見る併用パターン
「全部Playwright APIに移行」ではなく、「シンプルなAPIテストはrequests、E2E統合が必要なものはPlaywright API」という併用が実務では保守コストと運用効率のバランスが良い。2ツールは競合ではなく、相互補完の関係だ。
⚠️ Playwright APIが向いていないケース
- 大量並列API負荷試験:Playwright APIは負荷テストツールではない。数百〜数千リクエストの並列送信にはLocust・k6等の専用ツールが合理的だ
- asyncioベースの非同期APIテスト:同期版Playwrightが主流のため、async/await前提の設計には
httpx + pytest-asyncioの方が自然だ - E2Eを使わない純粋なAPIテスト専用チーム:Playwright全体の導入コストに見合わない場合がある。requestsで十分な場合は無理に移行しなくてよい
- CI環境でインストール容量を最小化したい場合:Playwrightはブラウザバイナリを伴うため、軽量なAPIテスト用Dockerイメージではrequestsの方が有利だ
📖 関連記事
実務での推奨構成|Session・fixture・conftest.py
requests.Session() を使うべき場面
ログイン後に複数のAPIを叩くシナリオでは requests.Session() が非常に強力だ。Cookieや認証ヘッダーを自動で引き継ぎ、接続も再利用できる。
import pytest
import requests
BASE_URL = "https://restful-booker.herokuapp.com"
@pytest.fixture(scope="session")
def auth_session() -> requests.Session:
session = requests.Session()
# 共通ヘッダーを一括設定
session.headers.update({
"Content-Type": "application/json",
"Accept": "application/json"
})
# 認証してCookieを取得
response = session.post(
f"{BASE_URL}/auth",
json={"username": "admin", "password": "password123"},
timeout=(3, 10)
)
response.raise_for_status() # HTTPエラーを即検知
data = response.json()
assert "token" in data, "認証レスポンスにtokenが含まれていない"
token = data["token"]
session.cookies.set("token", token)
yield session # yieldで後処理が走るようにする
session.close() # テスト終了後にセッションを確実に解放
def test_セッションで予約一覧を取得(auth_session: requests.Session):
response = auth_session.get(f"{BASE_URL}/booking", timeout=(3, 10))
assert response.status_code == 200
assert len(response.json()) > 0conftest.py を使った推奨ディレクトリ構成
tests/
├── conftest.py # 共通fixture(auth_session, api_context等)
├── api/
│ ├── test_booking.py # requestsベースのAPIテスト
│ └── test_auth.py
└── e2e/
├── test_login.py # PlaywrightベースのE2Eテスト
└── test_booking_ui.pyconftest.py に auth_session(requests用)と api_context(Playwright用)の両fixtureを定義しておくと、テストファイル側はimportなしで使える。E2Eでしか書けない部分はPlaywright、シンプルなAPI確認はrequestsと使い分ける構成が保守コストと運用効率のバランスが良い。FAQ|よくある質問
Q. requestsは今後使われなくなりますか?
そうはならないと考えていい。requestsは2024〜2026年現在も依然として広く採用されており、PyPI週間ダウンロード数はトップクラスだ。httpxの普及が進んでいるのは事実だが、同期APIテストに特化したrequestsのシンプルさは今後も強みとして残る。「requestsから乗り換えなければならない」状況は基本的にない。
Q. Playwright APIだけでバックエンドAPIテストは完結できますか?
技術的には可能だ。APIRequestContext を使えばGET/POST/PUT/DELETE・認証・JSONアサーションまで一通りこなせる。ただし純粋なAPIテスト専用なら、requestsの方が軽量でコードもシンプルになる。Playwright APIが真価を発揮するのはE2EとAPIを同一コードベースで統合するときだ。「APIテストだけのためにPlaywrightを導入する」のは、チームがPlaywrightを使っていない限り過剰投資になりやすい。
Q. httpxはなぜ比較対象にしないのですか?
httpx は requests と互換性の高いAPIを持ちつつ、非同期(asyncio)にも対応したモダンなHTTPクライアントだ。2026年現在、async ベースのAPIテストやFastAPIプロジェクトとの親和性が高く注目されている。本記事ではまず最も広く使われる requests との比較に絞ったが、非同期APIテストが必要な場合は httpx + pytest-asyncio の組み合わせも有力な選択肢だ。
Q. api.dispose() をしないとどうなりますか?
dispose() を呼ばないと、APIコンテキストが保持するネットワーク接続やCookieが解放されない。テスト1件程度なら問題になりにくいが、大量のテストを実行する場合にはリソースリークの原因になりうる。そのため実務ではfixture化して yield 後の teardown で dispose() を呼ぶ設計が推奨だ。try/finally でラップするとassert失敗時も確実に解放できる。
Q. requests.Session() は使うべきですか?
複数のAPIリクエストをまとめて送る場合は積極的に使うべきだ。requests.Session() は接続を再利用し、Cookie・認証ヘッダーを自動で引き継ぐため、ログイン後に複数のAPIを叩くシナリオで特に便利だ。scope="session" のpytest fixtureと組み合わせると、テストスイート全体で1回の認証で使い回せる。単発のAPIテストなら不要だが、認証が絡む場合はほぼ必須と考えてよい。
Q. requestsとPlaywright APIは同時に使ってもいいですか?
もちろん問題ない。「シンプルなREST APIの確認はrequests、E2Eと組み合わせる部分はPlaywright API」というように、1つのプロジェクト内で併用するチームも多い。どちらか一方に統一する必要はなく、テストの目的に応じて使い分けるのが実務的な正解だ。
Q. pytest-playwrightがなくてもPlaywright APIは使えますか?
使える。sync_playwright() を使えばプラグインなしでAPIテストを書ける。以下が最小構成例だ。
# pytest-playwrightを使わない最小構成
from playwright.sync_api import sync_playwright
def test_ユーザー一覧取得():
with sync_playwright() as p:
api = p.request.new_context(
base_url="https://jsonplaceholder.typicode.com"
)
response = api.get("/users", timeout=10_000)
assert response.status == 200
users = response.json()
assert len(users) > 0
api.dispose()playwright fixture を活用した書き方(本記事のコード例)では pytest-playwright があると便利だが、必須ではない。小規模なAPIテストだけなら sync_playwright() で十分だ。
Q. Playwright APIはAPIテスト専用モードで動かせますか?
動かせる。playwright.request.new_context() を使えばブラウザを起動せずHTTPリクエストのみ実行できる。ただし一般的なPlaywrightセットアップでは playwright install によるブラウザバイナリのインストールを伴うため、requestsより初期セットアップが重めになりやすい。APIテストのみなら実行時にブラウザプロセスは不要だ。
Q. requestsのtimeoutはどう設定すべきですか?
timeout=(3, 10) のタプル形式が推奨だ。最初の3秒が接続タイムアウト、10秒が読み取りタイムアウトを意味する。タイムアウトなしでテストを実行すると、ネットワーク障害時にテストが無限に待ち続けるリスクがある。timeout=None は本番テストでは使わないようにしよう。
Q. APIテストの学習ロードマップはどうすればいいですか?
Python QAエンジニアとして最も実務的な順序は「requests + pytest(基礎)→ Playwright API(E2E統合)」だ。requestsでHTTPの基礎(GET/POST/認証/アサーション)を身につけてからPlaywright APIに移ると、new_context()の意味やdisposeの必要性が体感レベルで理解できる。
Q. JSTQB的にはAPIテストはどのレベルに分類されますか?
JSTQBのシラバスでは、APIテストは主に「コンポーネント統合テスト」や「システムテスト」の文脈で言及される。「サービス間の連携を確認する統合テスト」として位置づけられることが多く、テストピラミッドではUnit(単体)とE2Eの中間に位置する。ツール名は特定されず、目的と設計原則が問われる。
まとめ
📋 この記事のまとめ
- APIテストのみなら requests + pytest が最もシンプルで学習コストが低い
- E2EテストにPlaywrightを使っているなら Playwright API に統合する価値が高い
- 「UIで操作した結果をAPIで検証する」統合テストを同一コードベースで自然に統合しやすいのは Playwright APIの大きな強みだ
- 2ツールは競合ではなく 目的に応じた使い分け・併用が正解
- 学習順序は「requests → Playwright API」が体感での理解につながる
requestsとPlaywright API、どちらが優れているかではなく「自分のチームに何が必要か」で選ぶことが大切だ。迷ったときはこの記事のチェックリストと判断フローを参考にしてほしい。

