GuzzleHttp client
Отладка запроса
Guzzle умеет выводить запрос в STDOUT, для этого надо указать параметр ['debug' => true] при запросе.
Подробнее в документации.
Request
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
$request = new Request('GET', 'http://my-site.loc');
$client = new Client();
$response = $client->send($request);
Отправить json можно так:
Библиотека сама пропишет заголовокContent-Type: application/json и вызовет \GuzzleHttp\Utils::jsonEncode, которая является обёрткой над json_encode.
Минус такого способа — нельзя передать в json_encode флаги.
Кроме json поддерживаются и другие типы. Смотреть тут: \GuzzleHttp\Client::applyOptions()
Middleware
Мидлвар — выполняемая функция, которая параметром принимает callable $handler — следующий обработчик. Мидлвар должен вернуть новую функцию, которая принимает параметрами Psr\Http\Message\RequestInterface и массив опций. Функция должна вернуть $handler($request, options).
Мидлвары добавляются к хендлерам. Если при создании клиента не указывать хендлеры, библиотека сама запускает определение нужного хендлера через \GuzzleHttp\Utils::chooseHandler().
Если нужен дефолтный хендлер — можно воспользоваться просто конструктором. Если надо указать конкретный хендлер — можно заиспользовать статический метод \GuzzleHttp\HandlerStack::create().
Так например можно создавать mockHandler для тестирования.
$myMiddleware = static function (callable $handler) {
return static function (\Psr\Http\Message\RequestInterface $request, array $options) use ($handler) {
return $handler($request, $options);
}
};
$stack = \GuzzleHttp\HandlerStack::create();
$stack->push($myMiddleware);
$client = new \GuzzleHttp\Client(['handler' => $stack]);
$client->post('/api', ['json' => ['key' => 'value']]);
Установка заголовка Host
Необходимо установить Host отличный от того, что передан в base_uri.
Заиспользуем Middleware, и с помощью $request->withHeader создадим новый $request с установленным заголовком.
$myMiddleware = static function (callable $handler) {
return static function (\Psr\Http\Message\RequestInterface $request, array $options) use ($handler) {
$request = $request->withHeader('Host', 'my-site.loc');
return $handler($request, $options);
};
};
$stack = HandlerStack::create();
$stack->push($myMiddleware);
$client = new \GuzzleHttp\Client([
'base_uri' => 'https://localhost:443/',
RequestOptions::DEBUG => true,
RequestOptions::VERIFY => false,
'handler' => $stack,
]);
Логгирование Request с помощью middleware
$logMiddleware = static function (callable $handler) {
return static function (\Psr\Http\Message\RequestInterface $request, array $options) use ($handler) {
file_put_contents('/tmp/request.log', $request->getBody()->getContents(), FILE_APPEND);
return $handler($request, $options);
}
};
$stack = \GuzzleHttp\HandlerStack::create();
$stack->push($logMiddleware);
$client = new \GuzzleHttp\Client(['handler' => $stack]);
$client->post('/api', ['json' => ['key' => 'value']]);
Логгирование с использованием библиотеки Monolog
$logger = new \Monolog\Logger('guzzleLogger', [
// для примера логгер будет писать данные прямо в STDOUT
new \Monolog\Handler\StreamHandler(STDOUT)
]);
$debugLog = static function(callable $handler) use ($logger) {
return static function (\Psr\Http\Message\RequestInterface $request, array $options) use ($handler, $logger) {
$logger->info($request->getBody()->getContents());
return $handler($request, $options);
};
};
$stack = \GuzzleHttp\HandlerStack::create();
$stack->push($logMiddleware);
$client = new \GuzzleHttp\Client(['handler' => $stack]);
$client->post('/api', ['json' => ['key' => 'value']]);
Guzzle предоставляет несколько готовых Мидлваров (\GuzzleHttp\Middleware), в том числе и для логгинга — \GuzzleHttp\Middleware::log().
Удобно что первым параметром принимает Psr\Log\LoggerInterface, значит подружится с Monolog.
А вот вторым параметром принимает свой интерфейс \GuzzleHttp\MessageFormatterInterface.
$logger = new \Monolog\Logger('guzzleLogger', [
// для примера логгер будет писать данные прямо в STDOUT
new \Monolog\Handler\StreamHandler(STDOUT)
]);
$stack = \GuzzleHttp\HandlerStack::create();
$stack->push(\GuzzleHttp\Middleware::log(
$logger,
new \GuzzleHttp\MessageFormatter('Тут можно передать шаблон, пример в исходниках')
));
$client = new \GuzzleHttp\Client(['handler' => $stack]);
$client->post('/api', ['json' => ['key' => 'value']]);
Тестирование
О тестировании написано в документации
Пример: Сервис MyService формирует и отправляет данные в формате json. Необходимо протестировать формат пакета в phpUnit без отправки запроса.
use GuzzleHttp\Client;
class MyService
{
private Client $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function run()
{
$payload = []; // данные для отправки
$response = $this->client->post('endpoint', $payload);
}
}
Для этого заиспользуем Mock Handler + History Middleware. Использование Mock Handler предотвратит отправку данных, а с помощью History Middleware достанем body. В нашем случае body в формате json. Применив json_decode, получим набор отправляемых данных.
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\TestCase;
class MyServiceTest extends TestCase
{
private MyService $service;
public array $historyContainer;
public function setUp(): void
{
$this->historyContainer = [];
$mock = new MockHandler([
// в данном случае структура ответа не важна
new Response(200, [], ''),
]);
$handlerStack = HandlerStack::create($mock);
$history = Middleware::history($this->historyContainer);
$handlerStack->push($history);
$client = new Client(['handler' => $handlerStack]);
$this->service = new MyService($client);
}
public function testRun()
{
$this->service->run();
/** @var Request $request */
$request = current($this->historyContainer)['request'];
$body = $request->getBody();
$body->rewind();
$data = json_decode($body->getContents(), true);
$this->assertArrayHasKey('foo', $data, 'Отсутствует необходимый параметр');
}
}
Авторизация в Битрикс
Для того чтоб куки сохранялись между запросами, надо установить cookies в true в конструкторе (документация):
Теперь можно авторизоваться в Битрикс и отправлять запросы как авторизованный пользователь:
$client = new \GuzzleHttp\Client([
'base_uri' => 'https://my-site.loc',
'cookies' => true,
]);
// авторизация в Битрикс
$client->post('/', [
'form_params' => [
'AUTH_FORM' => 'Y',
'TYPE' => 'AUTH',
'USER_LOGIN' => 'login',
'USER_PASSWORD' => 'password'
]],
);
$response = $client->get('/crm/lead/list/');
$contents = $response->getBody()->getContents();