Fazendo requisições HTTP
O Yii não inclui uma implementação própria de cliente HTTP. Use um cliente que implemente a PSR-18 e dependa das interfaces PSR no código da sua aplicação.
Esta receita usa o Guzzle como cliente HTTP. O Guzzle fornece um cliente PSR-18 e usa mensagens PSR-7.
Instalação
Instale o Guzzle:
composer require guzzlehttp/guzzleO pacote instala as interfaces HTTP da PSR e o guzzlehttp/psr7, que fornece mensagens PSR-7 e factories PSR-17.
Configure o container
Crie config/common/di/http-client.php:
<?php
declare(strict_types=1);
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\UriFactoryInterface;
use Yiisoft\Definitions\Reference;
return [
ClientInterface::class => [
'class' => Client::class,
'__construct()' => [
'config' => [
'timeout' => 10.0,
'connect_timeout' => 3.0,
],
],
],
HttpFactory::class => HttpFactory::class,
RequestFactoryInterface::class => Reference::to(HttpFactory::class),
ResponseFactoryInterface::class => Reference::to(HttpFactory::class),
StreamFactoryInterface::class => Reference::to(HttpFactory::class),
UriFactoryInterface::class => Reference::to(HttpFactory::class),
];Use ClientInterface para enviar requisições e as factories PSR-17 para criar requisições, streams e URIs.
Envie uma requisição GET
Injete Psr\Http\Client\ClientInterface e Psr\Http\Message\RequestFactoryInterface no serviço que conversa com a API externa:
<?php
declare(strict_types=1);
namespace App\GitHub;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use RuntimeException;
final readonly class ReleaseClient
{
public function __construct(
private ClientInterface $httpClient,
private RequestFactoryInterface $requestFactory,
) {
}
/**
* @return array<string, mixed>
*/
public function latest(string $owner, string $repository): array
{
$request = $this->requestFactory
->createRequest(
'GET',
sprintf(
'https://api.github.com/repos/%s/%s/releases/latest',
rawurlencode($owner),
rawurlencode($repository),
),
)
->withHeader('Accept', 'application/vnd.github+json');
try {
$response = $this->httpClient->sendRequest($request);
} catch (ClientExceptionInterface $e) {
throw new RuntimeException('GitHub request failed.', previous: $e);
}
if ($response->getStatusCode() !== 200) {
throw new RuntimeException(sprintf(
'GitHub returned HTTP %d.',
$response->getStatusCode(),
));
}
return json_decode((string) $response->getBody(), true, 512, JSON_THROW_ON_ERROR);
}
}Clientes PSR-18 lançam ClientExceptionInterface para erros no envio da requisição. Códigos de status HTTP como 404 e 500 são respostas válidas, então verifique o código de status no seu serviço.
Envie JSON
Use StreamFactoryInterface quando precisar de um corpo na requisição:
<?php
declare(strict_types=1);
namespace App\Webhook;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
final readonly class WebhookClient
{
public function __construct(
private ClientInterface $httpClient,
private RequestFactoryInterface $requestFactory,
private StreamFactoryInterface $streamFactory,
) {
}
/**
* @param array<string, mixed> $payload
*/
public function send(array $payload): void
{
$body = $this->streamFactory->createStream(json_encode($payload, JSON_THROW_ON_ERROR));
$request = $this->requestFactory
->createRequest('POST', 'https://api.example.com/webhooks')
->withHeader('Content-Type', 'application/json')
->withHeader('Accept', 'application/json')
->withBody($body);
$this->httpClient->sendRequest($request);
}
}Testes
Para testes unitários, passe um cliente configurado com o MockHandler do Guzzle:
<?php
declare(strict_types=1);
use App\GitHub\ReleaseClient;
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\HttpFactory;
use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\TestCase;
final class ReleaseClientTest extends TestCase
{
public function testLatestReturnsDecodedRelease(): void
{
$handler = new MockHandler([
new Response(200, [], json_encode(['tag_name' => '1.0.0'], JSON_THROW_ON_ERROR)),
]);
$client = new Client(['handler' => HandlerStack::create($handler)]);
$factory = new HttpFactory();
$releaseClient = new ReleaseClient($client, $factory);
$release = $releaseClient->latest('yiisoft', 'docs');
$this->assertSame('1.0.0', $release['tag_name']);
}
}Quando usar o Guzzle diretamente
Dependa das interfaces PSR nos serviços comuns da aplicação. Use GuzzleHttp\Client diretamente em código de infraestrutura que precise de recursos exclusivos do Guzzle, como requisições assíncronas, handler stacks ou middleware.