requests vs Playwright API【2026年版】|PythonでAPIテストするならどちらを選ぶべきか

テスト自動化

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に統一したい」という声が出てくる。

💡 なぜこの2ツールで迷うのか:実務では「E2EはPlaywright、APIテストはrequests」でリポジトリを分けているチームも多い。その結果、fixtureの管理やレポート基盤が二重化しやすい。この問題を解決するために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について:近年はFastAPIやasyncioベースのプロジェクトで 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()
⚠️ timeout未指定はCIハングの原因になるrequests.get(url) と書くと timeout がデフォルト無制限になる。ネットワーク障害時にCIが数十分ハングするリスクがあるため、実務では必ず timeout=(接続秒, 読み取り秒) を明示しよう。
💡 GETの差
単純なGETなら requests の方がコードが短くシンプルだ。実務Tipとして、requestsでは response.raise_for_status() を使うことで4xx/5xxを例外化できる。なおPlaywright APIには同等メソッドはないため、通常は assert response.status == 200 のように明示的に検証する。どちらのアプローチも実務では広く使われている。

⚠️ response.json() の落とし穴:実務では障害時にHTMLエラーページが返るAPIが意外と多い。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()
💡 POSTの差
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は非常に合理的な選択だ。

💡 expect() と assert の使い分け
Playwrightでは UI要素の待機込みアサーションには expect(locator) を使い、APIレスポンスの確認には通常の assert を使う構成が実務では一般的だ。expect() はAuto-waitが働くため、要素の表示を待ちながら検証できる。APIの response.statusresponse.json() には assert で十分だ。

requestsの強みと弱み

✅ 強み⚠️ 弱み
  • 学習コストが最も低い(HTTP知識があればすぐ書ける)
  • コードがシンプルで読みやすい
  • インストールが軽量(ブラウザ不要)
  • pytest との組み合わせが成熟している
  • Stack Overflow等の情報量が圧倒的に多い
  • APIテストで特に広く使われるHTTPクライアントで実績が豊富
  • requests.Session() で接続再利用・Cookie共有も簡単に実現できる
  • E2EテストとAPIテストを統合できない
  • ネットワーク傍受・モックは別途ライブラリが必要
  • Session管理を明示的に行う必要がある(requests.Session() を使うことで強力な接続再利用が可能)
  • ブラウザ経由のAPIは叩けない

Playwright APIの強みと弱み

✅ 強み⚠️ 弱み
  • E2EテストとAPIテストを同一コードで統合できる
  • E2Eテスト側では page.route() によるネットワーク傍受・モックを標準機能で利用可能
  • E2Eブラウザ起動なしでAPIテストを実行可能(E2Eテストに比べれば高速)
  • Playwright E2Eとfixtureを共有できる
  • Allureレポートとの連携が自然
  • API単体なら導入可能だが、E2E統合まで使うと学習範囲が広がる
  • 一般的なセットアップではブラウザバイナリのインストールを伴うため、requestsより環境構築が重めになりやすい
  • APIのみのテストなら requestsより冗長になりがち
  • APIRequestContextは生成・解放の概念があるため、実務ではfixture化してライフサイクルを共通管理する構成が一般的

どちらを選ぶか|判断フロー

▶ 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()) > 0

conftest.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.py
💡 構成のポイント
conftest.pyauth_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はなぜ比較対象にしないのですか?

httpxrequests と互換性の高い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、どちらが優れているかではなく「自分のチームに何が必要か」で選ぶことが大切だ。迷ったときはこの記事のチェックリストと判断フローを参考にしてほしい。

タイトルとURLをコピーしました