本文へ移動
Laravel Tips

ほかのサービスの API を呼ぶ(HTTP クライアント)

ほかのサービスの API へリクエストを送る Http ファサードの使い方を説明します。データの送り方、認証、再試行、エラー、同時実行、テストの書き方を扱います。

アプリを作っていると、ほかのサービスの API(プログラムどうしがやりとりするための窓口)にデータを聞きに行ったり、送ったりしたいことがあります。たとえば、天気のサービスに「今日の天気は?」と聞くような場面です。Laravel の HTTP クライアントは、そのための道具です。中では Guzzle という PHP のパッケージが動いていますが、Laravel は、よく使う使い方に絞って、書きやすくしてくれています。

リクエストを送る#

リクエストは、Http ファサード(:: で呼べる窓口)の head・get・post・put・patch・delete で送ります。まず、ほかの URL へ GET リクエストを送る、いちばん簡単な例です。

php
use Illuminate\Support\Facades\Http;

$response = Http::get('http://example.com');

get は Illuminate\Http\Client\Response を返します。このオブジェクトの次のメソッドで、レスポンスを調べられます。

php
$response->body() : string;
$response->json($key = null, $default = null, $flags = null) : mixed;
$response->object() : object;
$response->collect($key = null) : Illuminate\Support\Collection;
$response->resource() : resource;
$response->status() : int;
$response->successful() : bool;
$response->redirect(): bool;
$response->failed() : bool;
$response->clientError() : bool;
$response->header($header) : string;
$response->headers() : array;
メソッド 説明
body レスポンスの本文を、文字列で返す
json 本文を JSON として読み、配列などに直して返す。キーや初期値も渡せる
object 本文を JSON として読み、オブジェクトで返す
collect 本文を JSON として読み、コレクション(配列を便利に扱う入れ物)で返す
resource 本文を、resource(ファイルのように読める値)で返す
status ステータスコード(結果を表す番号)を返す
successful ステータスコードが成功(200 以上 300 未満)か
redirect 転送のレスポンスか
failed ステータスコードが 400 以上か
clientError ステータスコードが 400 番台か
header 決めたヘッダー(レスポンスに付く説明書き)の値を返す
headers すべてのヘッダーを配列で返す

Illuminate\Http\Client\Response は、PHP の ArrayAccess(配列のように読める約束ごと)も実装しています。そのため、JSON のレスポンスの値を、配列のように、そのまま取り出せます。

php
return Http::get('http://example.com/users/1')['name'];

上のメソッドに加えて、決まったステータスコードかを調べるメソッドもあります。

php
$response->ok() : bool;                  // 200 OK
$response->created() : bool;             // 201 Created
$response->accepted() : bool;            // 202 Accepted
$response->noContent() : bool;           // 204 No Content
$response->movedPermanently() : bool;    // 301 Moved Permanently
$response->found() : bool;               // 302 Found
$response->badRequest() : bool;          // 400 Bad Request
$response->unauthorized() : bool;        // 401 Unauthorized
$response->paymentRequired() : bool;     // 402 Payment Required
$response->forbidden() : bool;           // 403 Forbidden
$response->notFound() : bool;            // 404 Not Found
$response->requestTimeout() : bool;      // 408 Request Timeout
$response->conflict() : bool;            // 409 Conflict
$response->unprocessableEntity() : bool; // 422 Unprocessable Entity
$response->tooManyRequests() : bool;     // 429 Too Many Requests
$response->serverError() : bool;         // >= 500 Server Error
メソッド 説明
ok 200(成功)か
created 201(作成した)か
accepted 202(受け付けた)か
noContent 204(内容なし)か
movedPermanently 301(恒久的に引っ越した)か
found 302(見つかった。転送)か
badRequest 400(リクエストが不正)か
unauthorized 401(ログインが必要)か
paymentRequired 402(支払いが必要)か
forbidden 403(禁止)か
notFound 404(見つからない)か
requestTimeout 408(リクエストが時間切れ)か
conflict 409(食い違いがある)か
unprocessableEntity 422(処理できない内容)か
tooManyRequests 429(リクエストが多すぎる)か
serverError 500 以上(サーバー側のエラー)か

URI テンプレート#

リクエストの URL は、URI テンプレート({page} のような入れ場所を書いた、URL のひな形)の決まり(RFC 6570)でも作れます。入れ場所に入れる値は、withUrlParameters で決めます。

php
Http::withUrlParameters([
    'endpoint' => 'https://laravel.com',
    'page' => 'docs',
    'version' => '13.x',
    'topic' => 'validation',
])->get('{+endpoint}/{page}/{version}/{topic}');

リクエストを画面に出す#

送る前のリクエストを画面に出して、そこで止めたいときは、リクエストの書き始めに dd を足します。

php
return Http::dd()->get('http://example.com');

送るデータ#

POST・PUT・PATCH では、追加のデータを送るのがふつうです。そのため、これらのメソッドは、2つ目の引数にデータの配列を受け取ります。ふつう、データは application/json(JSON という種類)として送られます。

php
use Illuminate\Support\Facades\Http;

$response = Http::post('http://example.com/users', [
    'name' => 'Steve',
    'role' => 'Network Administrator',
]);

GET リクエストのクエリのパラメータ#

GET では、URL にクエリ文字列(?name=Taylor&page=1 のような、URL の後ろに付ける追加の指定)を直接足せます。あるいは、get の2つ目の引数に、キーと値の配列を渡せます。

php
$response = Http::get('http://example.com/users', [
    'name' => 'Taylor',
    'page' => 1,
]);

withQueryParameters でも書けます。

php
Http::retry(3, 100)->withQueryParameters([
    'name' => 'Taylor',
    'page' => 1,
])->get('http://example.com/users');

フォームの形式で送る#

データを application/x-www-form-urlencoded(HTML のフォームと同じ形式)で送りたいときは、リクエストの前に asForm を呼びます。

php
$response = Http::asForm()->post('http://example.com/users', [
    'name' => 'Sara',
    'role' => 'Privacy Consultant',
]);

本文をそのまま送る#

リクエストの本文をそのまま渡したいときは、withBody を使います。2つ目の引数で、コンテンツタイプ(データの種類を表す名前)を決められます。

php
$response = Http::withBody(
    base64_encode($photo), 'image/jpeg'
)->post('http://example.com/photo');

ファイルを送る(マルチパート)#

ファイルを、マルチパート(複数の部分に分けて送る形式)で送りたいときは、リクエストの前に attach を呼びます。名前とファイルの中身を渡します。必要なら、3つ目の引数にファイル名、4つ目の引数にそのファイルに付けるヘッダーを渡せます。

php
$response = Http::attach(
    'attachment', file_get_contents('photo.jpg'), 'photo.jpg', ['Content-Type' => 'image/jpeg']
)->post('http://example.com/attachments');

ファイルの中身そのものの代わりに、ストリームの resource(ファイルを少しずつ読むための値)も渡せます。

php
$photo = fopen('photo.jpg', 'r');

$response = Http::attach(
    'attachment', $photo, 'photo.jpg'
)->post('http://example.com/attachments');
メソッド 説明
withUrlParameters URI テンプレートで展開する、URL のパラメータを決める
withQueryParameters クエリのパラメータを決める
asForm フォームの形式で送る
withBody 本文をそのまま渡す。コンテンツタイプも渡せる
attach ファイルをマルチパートで送る
dd 送る前のリクエストを画面に出して止まる

ヘッダー#

ヘッダーは withHeaders で足せます。キーと値の配列を渡します。

php
$response = Http::withHeaders([
    'X-First' => 'foo',
    'X-Second' => 'bar'
])->post('http://example.com/users', [
    'name' => 'Taylor',
]);

レスポンスで受け取りたいコンテンツタイプは、accept で決めます。

php
$response = Http::accept('application/json')->get('http://example.com/users');

application/json を受け取りたいときは、acceptJson が近道です。

php
$response = Http::acceptJson()->get('http://example.com/users');

withHeaders は、すでにあるヘッダーに、新しいヘッダーを足し合わせます。ヘッダーをすべて入れかえたいときは、replaceHeaders を使います。

php
$response = Http::withHeaders([
    'X-Original' => 'foo',
])->replaceHeaders([
    'X-Replacement' => 'bar',
])->post('http://example.com/users', [
    'name' => 'Taylor',
]);
メソッド 説明
withHeaders ヘッダーを足す。すでにあるヘッダーとは足し合わせる
accept レスポンスで受け取りたいコンテンツタイプを決める
acceptJson application/json を受け取りたいと伝える
replaceHeaders ヘッダーを、すべて入れかえる

認証#

ベーシック認証(ユーザー名とパスワードで確かめる方法)とダイジェスト認証(パスワードをそのまま送らない方法)の情報は、それぞれ withBasicAuth と withDigestAuth で渡せます。

php
// ベーシック認証
$response = Http::withBasicAuth('taylor@laravel.com', 'secret')->post(/* ... */);

// ダイジェスト認証
$response = Http::withDigestAuth('taylor@laravel.com', 'secret')->post(/* ... */);

ベアラートークン#

リクエストの Authorization ヘッダーに、ベアラートークン(持っている人に権限を認める、合言葉のような文字列)を足したいときは、withToken が近道です。

php
$response = Http::withToken('token')->post(/* ... */);
メソッド 説明
withBasicAuth ベーシック認証の情報を渡す
withDigestAuth ダイジェスト認証の情報を渡す
withToken ベアラートークンを Authorization ヘッダーに足す

タイムアウト#

timeout で、レスポンスを待つ最大の秒数を決められます。ふつう、HTTP クライアントは 30 秒でタイムアウト(待ちきれずにあきらめること)します。

php
$response = Http::timeout(3)->get(/* ... */);

決めた時間を過ぎると、Illuminate\Http\Client\ConnectionException が出ます。

サーバーにつなぐのを待つ最大の秒数は、connectTimeout で決められます。ふつうは 10 秒です。

php
$response = Http::connectTimeout(3)->get(/* ... */);

再試行#

クライアント側やサーバー側のエラーのとき、HTTP クライアントに、自動でやり直させたいなら、retry を使います。retry は、リクエストを試す最大の回数と、試すあいだに待つミリ秒(1000分の1秒)を受け取ります。

php
$response = Http::retry(3, 100)->post(/* ... */);

試すあいだに待つ時間を自分で計算したいときは、2つ目の引数にクロージャ(名前のない関数)を渡します。

php
use Exception;

$response = Http::retry(3, function (int $attempt, Exception $exception) {
    return $attempt * 100;
})->post(/* ... */);

1つ目の引数に、配列を渡すこともできます。配列には、1回ごとに、次を試すまで待つミリ秒を並べます。

php
$response = Http::retry([100, 200])->post(/* ... */);

必要なら、3つ目の引数に、本当にやり直すかを決める関数(クロージャなど)を渡せます。たとえば、最初のリクエストで ConnectionException が出たときだけ、やり直したいときに使います。

php
use Illuminate\Http\Client\PendingRequest;
use Throwable;

$response = Http::retry(3, 100, function (Throwable $exception, PendingRequest $request) {
    return $exception instanceof ConnectionException;
})->post(/* ... */);

試みが失敗したとき、やり直す前に、リクエストを変えたいことがあります。そのときは、retry に渡した関数の中で、引数の $request を変えます。たとえば、最初の試みが認証のエラーだったら、新しい認証のトークンでやり直したい場合です。

php
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\RequestException;
use Throwable;

$response = Http::withToken($this->getToken())->retry(2, 0, function (Throwable $exception, PendingRequest $request) {
    if (! $exception instanceof RequestException || $exception->response->status() !== 401) {
        return false;
    }

    $request->withToken($this->getNewToken());

    return true;
})->post(/* ... */);

すべての試みが失敗すると、Illuminate\Http\Client\RequestException が出ます。これをやめたいときは、throw 引数に false を渡します。そうすると、すべてのやり直しのあとに、クライアントが最後に受け取ったレスポンスが返ります。

php
$response = Http::retry(3, 100, throw: false)->post(/* ... */);

注意

すべての試みが、つなぐこと自体の問題で失敗したときは、throw 引数を false にしても、Illuminate\Http\Client\ConnectionException が出ます。

メソッド・引数 説明
timeout レスポンスを待つ最大の秒数を決める。ふつうは 30 秒
connectTimeout つなぐのを待つ最大の秒数を決める。ふつうは 10 秒
retry 失敗したとき、決めた回数まで自動でやり直す
retry の throw 引数 false にすると、すべて失敗しても、最後のレスポンスを返す

エラーの扱い#

Guzzle のふつうの動きと違い、Laravel の HTTP クライアントは、クライアント側やサーバー側のエラー(サーバーが返す 400 番台や 500 番台のレスポンス)で例外を出しません。エラーが返ったかは、successful・failed・clientError・serverError で調べられます。

php
// ステータスコードが 200 以上 300 未満か
$response->successful();

// ステータスコードが 400 以上か
$response->failed();

// ステータスコードが 400 番台か
$response->clientError();

// ステータスコードが 500 番台か
$response->serverError();

// クライアント側かサーバー側のエラーのとき、渡した処理をすぐに動かす
$response->onError(callable $callback);

例外を出す#

レスポンスが手元にあって、ステータスコードがエラーのとき、Illuminate\Http\Client\RequestException を出したいなら、throw か throwIf を使います。

php
use Illuminate\Http\Client\Response;

$response = Http::post(/* ... */);

// クライアント側かサーバー側のエラーのとき、例外を出す
$response->throw();

// エラーで、かつ渡した条件が真のとき、例外を出す
$response->throwIf($condition);

// エラーで、かつ渡したクロージャが真を返すとき、例外を出す
$response->throwIf(fn (Response $response) => true);

// エラーで、かつ渡した条件が偽のとき、例外を出す
$response->throwUnless($condition);

// エラーで、かつ渡したクロージャが偽を返すとき、例外を出す
$response->throwUnless(fn (Response $response) => false);

// 決めたステータスコードのとき、例外を出す
$response->throwIfStatus(403);

// 決めたステータスコードでないとき、例外を出す
$response->throwUnlessStatus(200);

// サーバー側のエラー(500 以上)のとき、例外を出す
$response->throwIfServerError();

// クライアント側のエラー(400 以上 500 未満)のとき、例外を出す
$response->throwIfClientError();

return $response['user']['id'];
メソッド 説明
onError エラーのとき、渡した処理をすぐに動かす
throw エラーのとき、例外を出す
throwIf エラーで、かつ条件が真のとき、例外を出す
throwUnless エラーで、かつ条件が偽のとき、例外を出す
throwIfStatus 決めたステータスコードのとき、例外を出す
throwUnlessStatus 決めたステータスコードでないとき、例外を出す
throwIfServerError サーバー側のエラーのとき、例外を出す
throwIfClientError クライアント側のエラーのとき、例外を出す

Illuminate\Http\Client\RequestException には、公開の $response プロパティ(クラスの中の変数)があります。これで、返ってきたレスポンスを調べられます。

throw は、エラーが無ければ、レスポンスのオブジェクトをそのまま返します。そのため、あとにほかの処理をつなげられます。

php
return Http::post(/* ... */)->throw()->json();

例外が出る前に、ほかの処理もしたいときは、throw にクロージャを渡します。クロージャを動かしたあと、例外は自動で出ます。クロージャの中で例外を出し直す必要はありません。

php
use Illuminate\Http\Client\Response;
use Illuminate\Http\Client\RequestException;

return Http::post(/* ... */)->throw(function (Response $response, RequestException $e) {
    // ...
})->json();

ふつう、RequestException のメッセージは、記録されるときや報告されるとき、120 文字で切られます。この動きを変えたり止めたりしたいときは、bootstrap/app.php の registered の中で、truncateAt と dontTruncate を使います。

php
use Illuminate\Http\Client\RequestException;

->registered(function (): void {
    // リクエストの例外のメッセージを 240 文字で切る
    RequestException::truncateAt(240);

    // リクエストの例外のメッセージを切らない
    RequestException::dontTruncate();
})

リクエストごとに、メッセージを切る動きを変えたいときは、truncateExceptionsAt を使います。

php
return Http::truncateExceptionsAt(240)->post(/* ... */);

Guzzle のミドルウェア#

Laravel の HTTP クライアントは Guzzle で動いているので、Guzzle のミドルウェア(リクエストやレスポンスの途中に入る処理)を使って、送るリクエストを変えたり、届いたレスポンスを調べたりできます。送るリクエストを変えるには、withRequestMiddleware で Guzzle のミドルウェアを登録します。

php
use Illuminate\Support\Facades\Http;
use Psr\Http\Message\RequestInterface;

$response = Http::withRequestMiddleware(
    function (RequestInterface $request) {
        return $request->withHeader('X-Example', 'Value');
    }
)->get('http://example.com');

同じように、届いた HTTP のレスポンスを調べるには、withResponseMiddleware でミドルウェアを登録します。

php
use Illuminate\Support\Facades\Http;
use Psr\Http\Message\ResponseInterface;

$response = Http::withResponseMiddleware(
    function (ResponseInterface $response) {
        $header = $response->getHeader('X-Example');

        // ...

        return $response;
    }
)->get('http://example.com');

すべてのリクエストにかけるミドルウェア#

送るすべてのリクエストと、届くすべてのレスポンスにかけるミドルウェアを登録したいこともあります。globalRequestMiddleware と globalResponseMiddleware を使います。ふつうは、アプリの AppServiceProvider の boot メソッドで呼びます。

php
use Illuminate\Support\Facades\Http;

Http::globalRequestMiddleware(fn ($request) => $request->withHeader(
    'User-Agent', 'Example Application/1.0'
));

Http::globalResponseMiddleware(fn ($response) => $response->withHeader(
    'X-Finished-At', now()->toDateTimeString()
));
メソッド 説明
withRequestMiddleware 送るリクエストを変えるミドルウェアを登録する
withResponseMiddleware 届いたレスポンスを調べるミドルウェアを登録する
globalRequestMiddleware すべてのリクエストにかけるミドルウェアを登録する
globalResponseMiddleware すべてのレスポンスにかけるミドルウェアを登録する

Guzzle のオプション#

Guzzle のリクエストのオプションを、送るリクエストに足したいときは、withOptions を使います。キーと値の配列を渡します。

php
$response = Http::withOptions([
    'debug' => true,
])->get('http://example.com/users');

すべてのリクエストのオプション#

送るすべてのリクエストに、ふつうのオプションを決めたいときは、globalOptions を使います。ふつうは、アプリの AppServiceProvider の boot メソッドで呼びます。

php
use Illuminate\Support\Facades\Http;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Http::globalOptions([
        'allow_redirects' => false,
    ]);
}

同時にリクエストを送る#

複数の HTTP リクエストを、同時に送りたいことがあります。1つずつ順に送る代わりに、いくつかを同じときに送り出すのです。遅い API を相手にするとき、大きく速くなることがあります。

リクエストのプール#

これには pool を使います。pool には、Illuminate\Http\Client\Pool を受け取るクロージャを渡します。クロージャの中で足したリクエストが、まとめて送り出されます。

php
use Illuminate\Http\Client\Pool;
use Illuminate\Support\Facades\Http;

$responses = Http::pool(fn (Pool $pool) => [
    $pool->get('http://localhost/first'),
    $pool->get('http://localhost/second'),
    $pool->get('http://localhost/third'),
]);

return $responses[0]->ok() &&
       $responses[1]->ok() &&
       $responses[2]->ok();

このように、レスポンスは、プールに足した順番で取り出せます。as でリクエストに名前を付けると、名前でレスポンスを取り出せます。

php
use Illuminate\Http\Client\Pool;
use Illuminate\Support\Facades\Http;

$responses = Http::pool(fn (Pool $pool) => [
    $pool->as('first')->get('http://localhost/first'),
    $pool->as('second')->get('http://localhost/second'),
    $pool->as('third')->get('http://localhost/third'),
]);

return $responses['first']->ok();

プールの最大の同時の数は、pool の concurrency 引数で決められます。これは、送ったまま返事を待っていられる HTTP リクエストの、最大の数です。

php
$responses = Http::pool(fn (Pool $pool) => [
    // ...
], concurrency: 5);

プールのリクエストが、つなぐ段階で失敗したとき(たとえば、タイムアウトや、DNS(ドメイン名からサーバーの住所を調べるしくみ)の失敗)、$responses 配列のその項目は、Response ではなく Illuminate\Http\Client\ConnectionException になります。

php
foreach ($responses as $response) {
    if ($response instanceof Throwable) {
        // つなぐのに失敗した...
    } elseif ($response->failed()) {
        // つながったが、エラーのレスポンスを受け取った...
    }
}

同時のリクエストを設定する#

pool は、withHeaders や middleware など、HTTP クライアントのほかのメソッドとつなげられません。プールのリクエストに、ヘッダーやミドルウェアを付けたいときは、プールの中の、リクエストごとに設定します。

php
use Illuminate\Http\Client\Pool;
use Illuminate\Support\Facades\Http;

$headers = [
    'X-Example' => 'example',
];

$responses = Http::pool(fn (Pool $pool) => [
    $pool->withHeaders($headers)->get('http://laravel.test/test'),
    $pool->withHeaders($headers)->get('http://laravel.test/test'),
    $pool->withHeaders($headers)->get('http://laravel.test/test'),
]);

リクエストのバッチ#

同時にリクエストを送るもう1つの方法は、batch(まとめて送るリクエストのひと組)です。pool と同じように、Illuminate\Http\Client\Batch を受け取るクロージャを渡し、その中でリクエストを足します。さらに、終わったときの処理も決められます。

php
use Illuminate\Http\Client\Batch;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\RequestException;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;

$responses = Http::batch(fn (Batch $batch) => [
    $batch->get('http://localhost/first'),
    $batch->get('http://localhost/second'),
    $batch->get('http://localhost/third'),
])->before(function (Batch $batch) {
    // バッチは作られたが、まだリクエストは始まっていない...
})->progress(function (Batch $batch, int|string $key, Response $response) {
    // 1つのリクエストが、成功して終わった...
})->then(function (Batch $batch, array $results) {
    // すべてのリクエストが、成功して終わった...
})->catch(function (Batch $batch, int|string $key, Response|RequestException|ConnectionException $response) {
    // バッチのリクエストの失敗が見つかった...
})->finally(function (Batch $batch, array $results) {
    // バッチが終わった...
})->send();

pool と同じように、as でリクエストに名前を付けられます。

php
$responses = Http::batch(fn (Batch $batch) => [
    $batch->as('first')->get('http://localhost/first'),
    $batch->as('second')->get('http://localhost/second'),
    $batch->as('third')->get('http://localhost/third'),
])->send();

send を呼んで batch が始まったあとは、新しいリクエストを足せません。足そうとすると、Illuminate\Http\Client\BatchInProgressException が出ます。

バッチの最大の同時の数は、concurrency で決められます。これは、送ったまま返事を待っていられる HTTP リクエストの、最大の数です。

php
$responses = Http::batch(fn (Batch $batch) => [
    // ...
])->concurrency(5)->send();
メソッド 説明
before バッチが作られて、リクエストが始まる前に動く
progress 1つのリクエストが、成功して終わったときに動く
then すべてのリクエストが、成功して終わったときに動く
catch バッチのリクエストの失敗が見つかったときに動く
finally バッチが終わったときに動く
as リクエストに名前を付ける
concurrency 最大の同時の数を決める
send バッチを始める
defer レスポンスを返したあとに、バッチを動かす

バッチを調べる#

バッチが終わったときの処理に渡される Illuminate\Http\Client\Batch には、バッチを調べるための、いろいろなプロパティやメソッドがあります。

php
// バッチに割り当てられたリクエストの数
$batch->totalRequests;

// まだ処理されていないリクエストの数
$batch->pendingRequests;

// 失敗したリクエストの数
$batch->failedRequests;

// ここまでに処理されたリクエストの数
$batch->processedRequests();

// バッチが終わったか
$batch->finished();

// バッチに、失敗したリクエストがあるか
$batch->hasFailures();
プロパティ・メソッド 説明
totalRequests バッチに割り当てられたリクエストの数
pendingRequests まだ処理されていないリクエストの数
failedRequests 失敗したリクエストの数
processedRequests ここまでに処理されたリクエストの数
finished バッチが終わったか
hasFailures バッチに、失敗したリクエストがあるか

バッチを後回しにする#

defer を呼ぶと、バッチのリクエストは、すぐには動きません。代わりに、いまのアプリのリクエストへの HTTP のレスポンスを、ユーザーに返したあとで、Laravel がバッチを動かします。アプリを速く、軽く感じさせられます。

php
use Illuminate\Http\Client\Batch;
use Illuminate\Support\Facades\Http;

$responses = Http::batch(fn (Batch $batch) => [
    $batch->get('http://localhost/first'),
    $batch->get('http://localhost/second'),
    $batch->get('http://localhost/third'),
])->then(function (Batch $batch, array $results) {
    // すべてのリクエストが、成功して終わった...
})->defer();

マクロ#

HTTP クライアントでは、「マクロ」(自分で作る、名前の付いた書き方の近道)を作れます。アプリのあちこちのサービスと通信するとき、よく使うリクエストの宛先やヘッダーの設定を、短く書けます。まず、アプリの App\Providers\AppServiceProvider の boot メソッドの中で、マクロを作ります。

php
use Illuminate\Support\Facades\Http;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Http::macro('github', function () {
        return Http::withHeaders([
            'X-Example' => 'example',
        ])->baseUrl('https://github.com');
    });
}

マクロを作ったら、アプリのどこからでも呼べます。決めた設定のリクエストが作られます。

php
$response = Http::github()->get('/');

テスト#

Laravel のサービスの多くには、テストを楽に書ける機能があります。HTTP クライアントも同じです。Http ファサードの fake を使うと、リクエストが送られたとき、本物の代わりに、にせものの(ダミーの)レスポンスを返させられます。テストの基本はテストのはじめかたを見てください。

にせのレスポンスを返す#

たとえば、どのリクエストにも、内容が空の 200 を返させたいときは、fake を引数なしで呼びます。

php
use Illuminate\Support\Facades\Http;

Http::fake();

$response = Http::post(/* ... */);

決まった URL をにせものにする#

代わりに、fake に配列を渡せます。配列のキーが、にせものにしたい URL の形、値が、そのときのレスポンスです。* は、「何でもよい」を表すワイルドカードです。にせのレスポンスは、Http ファサードの response で作れます。

php
Http::fake([
    // GitHub の宛先に、JSON のレスポンスを返す
    'github.com/*' => Http::response(['foo' => 'bar'], 200, $headers),

    // Google の宛先に、文字列のレスポンスを返す
    'google.com/*' => Http::response('Hello World', 200, $headers),
]);

にせものにしていない URL へのリクエストは、実際に送られます。合わなかったすべての URL に返すものを決めたいときは、* だけの形を使います。

php
Http::fake([
    // GitHub の宛先に、JSON のレスポンスを返す
    'github.com/*' => Http::response(['foo' => 'bar'], 200, ['Headers']),

    // それ以外のすべての宛先に、文字列のレスポンスを返す
    '*' => Http::response('Hello World', 200, ['Headers']),
]);

簡単な、文字列・JSON・空のレスポンスは、レスポンスとして、文字列・配列・整数を渡すだけでも作れます。

php
Http::fake([
    'google.com/*' => 'Hello World',
    'github.com/*' => ['foo' => 'bar'],
    'chatgpt.com/*' => 200,
]);

例外をにせものにする#

HTTP クライアントがリクエストを送るとき、Illuminate\Http\Client\ConnectionException が出た場合のアプリの動きを、テストしたいことがあります。failedConnection で、つなぐのに失敗した例外を出させられます。

php
Http::fake([
    'github.com/*' => Http::failedConnection(),
]);

Illuminate\Http\Client\RequestException が出た場合のアプリの動きを、テストしたいときは、failedRequest を使います。

php
$this->mock(GithubService::class)
    ->shouldReceive('getUser')
    ->andThrow(
        Http::failedRequest(['code' => 'not_found'], 404)
    );

順番に変わるレスポンス#

1つの URL に、決めた順番で、いくつものにせのレスポンスを返させたいことがあります。Http::sequence で、レスポンスを組み立てます。

php
Http::fake([
    // GitHub の宛先に、決めた順番でレスポンスを返す
    'github.com/*' => Http::sequence()
        ->push('Hello World', 200)
        ->push(['foo' => 'bar'], 200)
        ->pushStatus(404),
]);

順番のレスポンスをすべて使い切ったあとのリクエストでは、例外が出ます。空になったときに返す、ふつうのレスポンスを決めたいときは、whenEmpty を使います。

php
Http::fake([
    // GitHub の宛先に、決めた順番でレスポンスを返す
    'github.com/*' => Http::sequence()
        ->push('Hello World', 200)
        ->push(['foo' => 'bar'], 200)
        ->whenEmpty(Http::response()),
]);

順番のレスポンスは返したいけれど、URL の形は決めなくてよいときは、Http::fakeSequence が使えます。

php
Http::fakeSequence()
    ->push('Hello World', 200)
    ->whenEmpty(Http::response());

クロージャで決める#

宛先ごとに返すレスポンスを、もっと複雑な決まりで決めたいときは、fake にクロージャを渡せます。クロージャは Illuminate\Http\Client\Request を受け取り、レスポンスを返します。どんなレスポンスを返すかは、クロージャの中で、必要な処理を使って決められます。

php
use Illuminate\Http\Client\Request;

Http::fake(function (Request $request) {
    return Http::response('Hello World', 200);
});

送ったリクエストを調べる#

にせのレスポンスを使っているとき、クライアントが受け取ったリクエストを調べて、アプリが正しいデータやヘッダーを送ったか確かめたいことがあります。Http::fake のあとに、Http::assertSent を呼びます。

assertSent には、Illuminate\Http\Client\Request を受け取るクロージャを渡します。クロージャは、そのリクエストが期待に合うかを、真偽で返します。テストが成功するには、渡した期待に合うリクエストが、少なくとも1つ送られている必要があります。

php
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;

Http::fake();

Http::withHeaders([
    'X-First' => 'foo',
])->post('http://example.com/users', [
    'name' => 'Taylor',
    'role' => 'Developer',
]);

Http::assertSent(function (Request $request) {
    return $request->hasHeader('X-First', 'foo') &&
           $request->url() == 'http://example.com/users' &&
           $request['name'] == 'Taylor' &&
           $request['role'] == 'Developer';
});

必要なら、assertNotSent で、決まったリクエストが送られていないことを確かめられます。

php
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;

Http::fake();

Http::post('http://example.com/users', [
    'name' => 'Taylor',
    'role' => 'Developer',
]);

Http::assertNotSent(function (Request $request) {
    return $request->url() === 'http://example.com/posts';
});

テストのあいだに、いくつのリクエストが「送られた」かは、assertSentCount で確かめられます。

php
Http::fake();

Http::assertSentCount(5);

テストのあいだに、リクエストが1つも送られていないことは、assertNothingSent で確かめられます。

php
Http::fake();

Http::assertNothingSent();

リクエストとレスポンスを記録する#

recorded で、すべてのリクエストと、それに対応するレスポンスを集められます。recorded は、Illuminate\Http\Client\Request と Illuminate\Http\Client\Response を含む配列の、コレクションを返します。

php
Http::fake([
    'https://laravel.com' => Http::response(status: 500),
    'https://nova.laravel.com/' => Http::response(),
]);

Http::get('https://laravel.com');
Http::get('https://nova.laravel.com/');

$recorded = Http::recorded();

[$request, $response] = $recorded[0];

recorded には、Request と Response を受け取るクロージャも渡せます。期待に合うリクエストとレスポンスの組だけに、しぼりこめます。

php
use Illuminate\Http\Client\Request;
use Illuminate\Http\Client\Response;

Http::fake([
    'https://laravel.com' => Http::response(status: 500),
    'https://nova.laravel.com/' => Http::response(),
]);

Http::get('https://laravel.com');
Http::get('https://nova.laravel.com/');

$recorded = Http::recorded(function (Request $request, Response $response) {
    return $request->url() !== 'https://laravel.com' &&
           $response->successful();
});

にせものにし忘れたリクエストを止める#

1つのテスト、またはテスト全体で、HTTP クライアントが送るリクエストが、すべてにせものにされていることを確かめたいときは、preventStrayRequests を呼びます。呼んだあとは、にせのレスポンスを決めていないリクエストは、本物の HTTP リクエストを送らず、例外を出します。

php
use Illuminate\Support\Facades\Http;

Http::preventStrayRequests();

Http::fake([
    'github.com/*' => Http::response('ok'),
]);

// "ok" のレスポンスが返る
Http::get('https://github.com/laravel/framework');

// 例外が出る
Http::get('https://laravel.com');

ほとんどの、にせものにし忘れたリクエストは止めたいけれど、決まったリクエストは動かしたいときもあります。そのときは、allowStrayRequests に、URL の形の配列を渡します。渡した形のどれかに合うリクエストは許され、それ以外のリクエストは、引き続き例外を出します。

php
use Illuminate\Support\Facades\Http;

Http::preventStrayRequests();

Http::allowStrayRequests([
    'http://127.0.0.1:5000/*',
]);

// このリクエストは動く
Http::get('http://127.0.0.1:5000/generate');

// 例外が出る
Http::get('https://laravel.com');
メソッド 説明
fake リクエストに、にせのレスポンスを返させる
response にせのレスポンスを作る
failedConnection つなぐのに失敗した例外を出させる
failedRequest リクエストが失敗した例外を作る
sequence 決めた順番で、いくつものにせのレスポンスを返させる
fakeSequence URL の形を決めずに、順番のにせのレスポンスを返させる
assertSent 期待に合うリクエストが、少なくとも1つ送られた
assertNotSent 期待に合うリクエストが、送られていない
assertSentCount 送られたリクエストの数が、期待した数である
assertNothingSent リクエストが1つも送られていない
recorded 送られたリクエストと、そのレスポンスの組を集める
preventStrayRequests にせものにしていないリクエストで、例外を出す
allowStrayRequests 決めた URL の形のリクエストだけ、にせものにしなくても許す

イベント#

HTTP リクエストを送る途中で、Laravel は3つのイベント(「〜が起きた」という知らせ)を出します。RequestSending は、リクエストを送る前、ResponseReceived は、リクエストへのレスポンスを受け取ったあと、ConnectionFailed は、リクエストへのレスポンスが無かったときに出ます。

RequestSending と ConnectionFailed には、どちらも公開の $request プロパティがあり、Illuminate\Http\Client\Request を調べられます。同じように、ResponseReceived には、$request と $response のプロパティがあり、Illuminate\Http\Client\Response を調べられます。これらのイベントのリスナー(知らせを受けて動く処理)は、アプリの中に作れます。

php
use Illuminate\Http\Client\Events\RequestSending;

class LogRequest
{
    /**
     * Handle the event.
     */
    public function handle(RequestSending $event): void
    {
        // $event->request ...
    }
}
イベント 説明
RequestSending リクエストを送る前に出る。$request を調べられる
ResponseReceived レスポンスを受け取ったあとに出る。$request と $response を調べられる
ConnectionFailed レスポンスが無かったときに出る。$request を調べられる

関連するページ#

公式ドキュメント(英語)

2026年10月5日時点の内容をもとに、日本語でまとめています。

ページの一覧