HTTP Client
Table of Contents
Introduction
Laravel は、Guzzle の HTTP client を中心に、最小限の API を提供し、他の webapplication と迅速に通信するための発信 types の HTTP requests を可能にします。Laravel の Guzzle ラッパーは、最も一般的な使用例と素晴らしい development 者エクスペリエンスに焦点を当てています。
Making Requests
リクエストを行うには、Http
facade が提供するhead
、GET
、post
、put
、patch
、delete
メソッドを使用することができます。まず、基本的なget
request を別の URL に送る方法を見てみましょう:
use Illuminate\Support\Facades\Http;
$response = Http::get('http://example.com');
get
method は、Illuminate\Http\Client\Response
のインスタンスを返します。これには、 response を検証するために使用できる様々なメソッドが提供されています。
$response->body() : string;
$response->json($key = null, $default = null) : mixed;
$response->object() : object;
$response->collect($key = null) : Illuminate\Support\Collection;
$response->status() : int;
$response->successful() : bool;
$response->redirect(): bool;
$response->failed() : bool;
$response->clientError() : bool;
$response->header($header) : string;
$response->headers() : array;
Illuminate\Http\Client\Response
object は、PHP のArrayAccess
インターフェースも実装しており、 response 上で直接 JSON response data にアクセスすることができます。
return Http::get('http://example.com/users/1')['name'];
上記に挙げた response メソッドに加えて、以下のメソッドは response が指定した status code を持っているかどうかを判断するために使用できます:
$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 Internal Server Error
URI テンプレート
HTTP client もURI テンプレート仕様 を使用して requestURL を構築することができます。 URI テンプレートによって展開できる URL パラメータを定義するためには、withUrlParameters
method を使用することができます:
Http::withUrlParameters([
'endpoint' => 'https://laravel.com',
'page' => 'docs',
'version' => '11.x',
'topic' => 'validation',
])->get('{+endpoint}/{page}/{version}/{topic}');
リクエストのダンプ
送信する前に request インスタンスを dump したい、そしてスクリプトの実行を terminate したい場合は、 request の定義の始めに dd
method を追加することができます:
return Http::dd()->get('http://example.com');
Request Data
もちろん、POST
、PUT
、PATCH
リクエストを作成する際には、追加の data を request と共に送信することが一般的です。したがって、これらのメソッドは第二引数として data の array を受け入れます。 default として、 data はapplication/json
の content type を使用して送信されます。
use Illuminate\Support\Facades\Http;
$response = Http::post('http://example.com/users', [
'name' => 'Steve',
'role' => 'Network Administrator',
]);
GET Request Query パラメータ
GET
request を作成する際、直接 URL に query ストリングを追加するか、または key/value のペアの array をget
method の第二引数として渡すことができます:
$response = Http::get('http://example.com/users', [
'name' => 'Taylor',
'page' => 1,
]);
または、withQueryParameters
method を使用することもできます:
Http::retry(3, 100)->withQueryParameters([
'name' => 'Taylor',
'page' => 1,
])->get('http://example.com/users')
フォーム URL エンコードリクエストの送信
application/x-www-form-urlencoded
の content type を使用して data を送信したい場合は、 request を行う前にasForm
の method を呼び出す必要があります:
$response = Http::asForm()->post('http://example.com/users', [
'name' => 'Sara',
'role' => 'Privacy Consultant',
]);
生の Request ボディの送信
withBody
method を利用すると、request を行う際に生の request ボディを提供することができます。 contenttype は method の 2 つ目の引数を通じて提供することができます:
$response = Http::withBody(
base64_encode($photo), 'image/jpeg'
)->post('http://example.com/photo');
マルチパートリクエスト
複数パートのリクエストとしてファイルを送信したい場合は、attach
method をご自身の request を作成する前に呼び出すべきです。この method は、ファイルの名前とその内容を受け付けます。必要に応じて、3 つ目の引数を提供してファイルのファイル名として考えることができ、4 つ目の引数はファイルに関連する headers を提供するために使用することができます:
$response = Http::attach(
'attachment', file_get_contents('photo.jpg'), 'photo.jpg', ['Content-Type' => 'image/jpeg']
)->post('http://example.com/attachments');
ファイルの生の内容を渡す代わりに、ストリームの resource を渡すことができます:
$photo = fopen('photo.jpg', 'r');
$response = Http::attach(
'attachment', $photo, 'photo.jpg'
)->post('http://example.com/attachments');
Headers
withHeaders
method を使用して、 Headers を requests に追加できます。このwithHeaders
method は、key / value ペアの array を受け入れます:
$response = Http::withHeaders([
'X-First' => 'foo',
'X-Second' => 'bar'
])->post('http://example.com/users', [
'name' => 'Taylor',
]);
あなたはaccept
の method を使用して、あなたの application が request に対する response で期待している content type を指定することができます:
$response = H“ttp::accept('application/json')->get('http://example.com/users');
便宜上、あなたの application があなたの request への response で application/json
content type を期待していることを素早く指定するために、acceptJson
method を使用することができます。
$response = Http::acceptJson()->get('http://example.com/users');
withHeaders
method は、新たな headers を request の既存の headers に merges します。必要に応じて、replaceHeaders
method を使用して、すべての headers を完全に置き換えることも可能です。
$response = Http::withHeaders([
'X-Original' => 'foo',
])->replaceHeaders([
'X-Replacement' => 'bar',
])->post('http://example.com/users', [
'name' => 'Taylor',
]);
Authentication
withBasicAuth
メソッドとwithDigestAuth
メソッドを使用して、基本認証とダイジェスト authentication の認証情報を指定することができます。それぞれ:
// Basic authentication...
$response = Http::withBasicAuth('taylor@laravel.com', 'secret')->post(/* ... */);
// Digest authentication...
$response = Http::withDigestAuth('taylor@laravel.com', 'secret')->post(/* ... */);
Bearer Tokens
もし素早く bearer token を request のAuthorization
header に追加したい場合は、withToken
method を使用することができます:
$response = Http::withToken('token')->post(/* ... */);
Timeout
timeout
method は、response を待つ最大秒数を指定するために使用できます。default では、HTTP client は 30 秒後にタイムアウトします。
$response = Http::timeout(3)->get(/* ... */);
指定された timeout を超えると、Illuminate\Http\Client\ConnectionException
のインスタンスがスローされます。
connectTimeout
method を使用してサーバーへの接続を試みる際の最大待機時間(秒)を指定することができます:
$response = Http::connectTimeout(3)->get(/* ... */);
Retries
もし、 client または サーバの error が発生した際に HTTP client が自動的に retry を request するようにしたい場合は、retry
method を使用することができます。retry
method は、 request を試行する最大回数と、 Laravel が試行間で待つべきミリ秒数を指定します:
$response = Http::retry(3, 100)->post(/* ... */);
試行間で sleep するミリ秒数を手動で計算したい場合は、retry
method の第二引数としてクロージャを渡すことができます:
use Exception;
$response = Http::retry(3, function (int $attempt, Exception $exception) {
return $attempt * 100;
})->post(/* ... */);
便宜上、retry
の method の最初の引数として、 array を提供することもできます。この array は、次の試行まで何ミリ秒 sleep するかを決定するために使用されます:
$response = Http::retry([100, 200])->post(/* ... */);
必要に応じて、retry
method に対して第三引数を渡すことができます。 第三引数は、再試行が実際に試みられるべきかどうかを判断する呼び出し可能なものでなければなりません。例えば、初回の request がConnectionException
に遭遇した場合にのみ、retry を行いたいと考えるかもしれません。
use Exception;
use Illuminate\Http\Client\PendingRequest;
$response = Http::retry(3, 100, function (Exception $exception, PendingRequest $request) {
return $exception instanceof ConnectionException;
})->post(/* ... */);
request attempt が失敗した場合、新しい attempt が行われる前に request を変更することをお勧めします。これは、retry
method に提供された呼び出し可能なものに提供された request 引数を変更することで達成できます。例えば、最初の attempt が authentication error を返した場合、新しい authorization token を持って request を retry することができます。
use Exception;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\RequestException;
$response = Http::withToken($this->getToken())->retry(2, 0, function (Exception $exception, PendingRequest $request) {
if (! $exception instanceof RequestException || $exception->response->status() !== 401) {
return false;
}
$request->withToken($this->getNewToken());
return true;
})->post(/* ... */);
すべてのリクエストが失敗すると、Illuminate\Http\Client\RequestException
のインスタンスがスローされます。この動作を無効にしたい場合は、false
の value を持つthrow
引数を提供することができます。無効にすると、すべてのリトライが試みられた後に、 client によって受け取られた最後の response が返されます。
$response = Http::retry(3, 100, throw: false)->post(/* ... */);
WARNING
すべての requests が接続問題のために失敗した場合でも、
throw
引数がfalse
に設定されている場合でも、Illuminate\Http\Client\ConnectionException
が throw されます。
Error Handling
Guzzle の default 動作とは異なり、Laravel の HTTP client ラッパーは、 client またはサーバーの errors (サーバーからの400
および500
レベルのレスポンス)に対して throw exceptions を行いません。これらの errors のうちの 1 つが返されたかどうかは、successful
、clientError
、またはserverError
メソッドを使用して判断できます:
// Determine if the status code is >= 200 and < 300...
$response->successful();
// Determine if the status code is >= 400...
$response->failed();
// Determine if the response has a 400 level status code...
$response->clientError();
// Determine if the response has a 500 level status code...
$response->serverError();
// Immediately execute the given callback if there was a client or server error...
$response->onError(callable $callback);
Exceptions のスロー
あなたが response インスタンスを持っており、 response status code が client またはサーバーの error を示している場合に、 Illuminate\Http\Client\RequestException
のインスタンスを throw したい場合は、 throw
または throwIf
メソッドを使用できます:
use Illuminate\Http\Client\Response;
$response = Http::post(/* ... */);
// Throw an exception if a client or server error occurred...
$response->throw();
// Throw an exception if an error occurred and the given condition is true...
$response->throwIf($condition);
// Throw an exception if an error occurred and the given closure resolves to true...
$response->throwIf(fn (Response $response) => true);
// Throw an exception if an error occurred and the given condition is false...
$response->throwUnless($condition);
// Throw an exception if an error occurred and the given closure resolves to false...
$response->throwUnless(fn (Response $response) => false);
// Throw an exception if the response has a specific status code...
$response->throwIfStatus(403);
// Throw an exception unless the response has a specific status code...
$response->throwUnlessStatus(200);
return $response['user']['id'];
Illuminate\Http\Client\RequestException
インスタンスには、公開の$response
プロパティがあり、これにより返された response を検査できます。
throw
method は、何の error も発生しなかった場合に、 response インスタンスを返し、他の操作を throw
method に連結することを可能にします:
return Http::post(/* ... */)->throw()->json();
例外がスローされる前に追加のロジックを実行したい場合は、クロージャをthrow
method に渡すことができます。例外はクロージャが呼び出された後に自動的にスローされるので、クロージャの中から例外を再スローする必要はありません:
use Illuminate\Http\Client\Response;
use Illuminate\Http\Client\RequestException;
return Http::post(/* ... */)->throw(function (Response $response, RequestException $e) {
// ...
})->json();
Guzzle Middleware
Laravel の HTTP client は Guzzle により動作しているため、Guzzle の middleware を使用して発信側の request を操作したり、着信側の response を検査することができます。発信側の request を操作するために、Guzzle の middleware をwithRequestMiddleware
method で 登録してください:
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');
同様に、withResponseMiddleware
method を使用して middleware を登録することで、受信した HTTP response を確認することができます。
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');
グローバル Middleware
時々、すべての発信 request と受信 response に適用する middleware を register したい場合があります。これを達成するためには、globalRequestMiddleware
とglobalResponseMiddleware
メソッドを使用することができます。通常、これらのメソッドは、アプリケーションのAppServiceProvider
の中のboot
method で呼び出されるべきです:
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()
));
Guzzle Options
次のように、withOptions
method を使用して、送信する request に対して追加のGuzzle request options を指定することができます。withOptions
method は、key/ value のペアの array を受け入れます:
$response = Http::withOptions([
'debug' => true,
])->get('http://example.com/users');
グローバル Options
すべての送信用の request に対して defaultoptions を設定するには、globalOptions
method を利用することができます。通常、この method は、application の AppServiceProvider
の boot
method から呼び出されるべきです:
use Illuminate\Support\Facades\Http;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Http::globalOptions([
'allow_redirects' => false,
]);
}
Concurrent Requests
時には、複数の HTTP requests concurrently を同時に行いたい場合があるかもしれません。つまり、リクエストを順番に発行するのではなく、同時に複数のリクエストを送信したいということです。これにより、遅い HTTP API とのやりとりにおいて大幅なパフォーマンスの向上をもたらすことができます。
幸いなことに、これは pool
method を使用して達成することができます。 pool
method は、 Illuminate\Http\Client\Pool
インスタンスを受け取るクロージャを受け付け、簡単に requests を request pool に追加して dispatch することができます:
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();
ご覧の通り、各々の response インスタンスはそれが pool に追加された順番でアクセス可能です。もしご希望であれば、as
method を使ってリクエストに名前を付けることができます。これにより、名前に基づいて対応するレスポンスにアクセスすることが可能になります。
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
method は、withHeaders
やmiddleware
のような他の HTTP client のメソッドと連携できません。プールされたリクエストに対して customheaders や middleware を適用したい場合は、それぞれの request に対してこれらの options を設定する必要があります。それぞれの request は、プール内で設定されます:
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'),
]);
Macros
Laravel HTTP client は、「マクロ」を定義することができます。これは、 application 全体で services とやりとりする際に一般的な request paths と headers を設定するための流れるような、表現力豊かなメカニズムとして機能します。始めるためには、boot
method 内に、お使いのアプリケーションの App\Providers\AppServiceProvider
class 内で macro を定義することができます。
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');
});
}
あなたの macro が設定されたら、あなたの application のどこからでもそれを呼び出して指定した設定で保留中の request を作成することができます。
$response = Http::github()->get('/');
Testing
多くの Laravel services は、容易かつ表現豊かにテストを書くための機能を提供しており、Laravel の HTTP client も例外ではありません。Http
ファサードのfake
method を使用すると、リクエストが行われたときに HTTP client がスタブ化/ダミーのレスポンスを返すように指示することができます。
レスポンスの偽装
たとえば、200
の status code の空の responses をすべての request に対して HTTP client に返すように指示するには、引数なしでfake
の method を呼び出すことができます。
use Illuminate\Support\Facades\Http;
Http::fake();
$response = Http::post(/* ... */);
特定の URL を偽装する
あるいは、fake
method に array を渡すことも可能です。その array の keys は、あなたが fake にしたい URL のパターンを表し、それらに関連するresponse
s です。*
はワイルドカード文字として使用できます。フェイクされていない URL への requests は実際に実行されます。これらのエンドポイントに対する stub / fake responses を構築するために、Http
facade の response
method を使用できます。
Http::fake([
// Stub a JSON response for GitHub endpoints...
'github.com/*' => Http::response(['foo' => 'bar'], 200, $headers),
// Stub a string response for Google endpoints...
'google.com/*' => Http::response('Hello World', 200, $headers),
]);
すべての一致しない URL をスタブにするフォールバックの URL パターンを指定したい場合は、single の *
文字を使用することができます:
Http::fake([
// Stub a JSON response for GitHub endpoints...
'github.com/*' => Http::response(['foo' => 'bar'], 200, ['Headers']),
// Stub a string response for all other endpoints...
'*' => Http::response('Hello World', 200, ['Headers']),
]);
Response シーケンスの偽造
場合によっては、 single URL が特定の順序で一連の fake の応答を返すように指定する必要があるかもしれません。これは、Http::sequence
method を使って応答を build することで達成できます:
Http::fake([
// Stub a series of responses for GitHub endpoints...
'github.com/*' => Http::sequence()
->push('Hello World', 200)
->push(['foo' => 'bar'], 200)
->pushStatus(404),
]);
すべての response sequence 内の応答が消費されたとき、それ以上のリクエストは response sequence を throw し、例外が発生します。 sequence が空の場合に返されるべき default response を指定したい場合は、whenEmpty
method を使用できます。
Http::fake([
// Stub a series of responses for GitHub endpoints...
'github.com/*' => Http::sequence()
->push('Hello World', 200)
->push(['foo' => 'bar'], 200)
->whenEmpty(Http::response()),
]);
もし、 fake の responses sequence を作りたいけれども、偽造すべき特定の URL パターンを指定する必要がない場合、Http::fakeSequence
method を使うことができます:
Http::fakeSequence()
->push('Hello World', 200)
->whenEmpty(Http::response());
Fake コールバック
もし特定のエンドポイントに対してどのレスポンスを返すかを決定するために、より複雑なロジックが必要な場合、fake
method にクロージャを渡すことができます。このクロージャはIlluminate\Http\Client\Request
のインスタンスを受け取り、 response インスタンスを返すべきです。クロージャ内では、どの type の response を返すかを決定するために必要なロジックを実行できます。
use Illuminate\Http\Client\Request;
Http::fake(function (Request $request) {
return Http::response('Hello World', 200);
});
ストレイリクエストの防止
もし全ての HTTP client を介したリクエストが個々のテストや完全なテストスイート全体で偽装されていることを確認したい場合、preventStrayRequests
method を呼び出すことができます。この method を呼び出した後、対応する fake response がないリクエストは、実際の HTTP request を行うのではなく、例外を throw します:
use Illuminate\Support\Facades\Http;
Http::preventStrayRequests();
Http::fake([
'github.com/*' => Http::response('ok'),
]);
// An "ok" response is returned...
Http::get('https://github.com/laravel/framework');
// An exception is thrown...
Http::get('https://laravel.com');
リクエストの検査
レスポンスを偽造する際には、あなたの application が正しい data または headers を送信していることを確認するために、 client が受け取るリクエストを確認したい場合があります。これは、 Http::fake
を呼び出した後に Http::assertSent
method を呼び出すことで実現できます。
assertSent
method は、Illuminate\Http\Client\Request
インスタンスを受け取り、request があなたの期待に一致しているかどうかを示すブール value を返すべきクロージャを受け入れます。test が path するためには、少なくとも 1 つの request が与えられた期待 value に一致して発行されていなければなりません:
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';
});
必要に応じて、特定の request が assertNotSent
method を使用して送信されなかったと assert することができます:
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';
});
テスト中に sent が何回送信されたかを assert するために、assertSentCount
method を使うことができます。
Http::fake();
Http::assertSentCount(5);
または、test 中に requests が送信されなかったことを assert するために、assertNothingSent
method を使用することもできます:
Http::fake();
Http::assertNothingSent();
リクエスト/レスポンスの記録
すべての requests とそれに対応する response を収集するために、recorded
method を使うことができます。recorded
method は、Illuminate\Http\Client\Request
と Illuminate\Http\Client\Response
のインスタンスを含む arrays の collection を返します:
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
method はクロージャを受け入れ、Illuminate\Http\Client\Request
およびIlluminate\Http\Client\Response
のインスタンスを受け取り、あなたの期待に基づいて request / response のペアをフィルタリングするために使用することができます:
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();
});
Events
Laravel は、 HTTP requests の送信 process 中に三つの events を発火します。RequestSending
event は、 request が送信される前に発火し、ResponseReceived
event は特定の request に対する response を受け取った後に発火します。特定の request に対する response が受け取られなかった場合、ConnectionFailed
event が発火します。
RequestSending
と ConnectionFailed
event の両方は、Illuminate\Http\Client\Request
インスタンスを調査するために使用できる $request
プロパティを公開( public )しています。同様に、ResponseReceived
events にも $request
プロパティと $response
プロパティが含まれており、これらを用いて Illuminate\Http\Client\Response
インスタンスを調査することができます。これらの events に対するevent listenersをあなたの application 内で作成することができます:
use Illuminate\Http\Client\Events\RequestSending;
class LogRequest
{
/**
* Handle the given event.
*/
public function handle(RequestSending $event): void
{
// $event->request ...
}
}