Skip to content

Commit

Permalink
Merge pull request #78 from tharropoulos/http-clients
Browse files Browse the repository at this point in the history
Fix HTTP client handling and configuration in Typesense PHP client
  • Loading branch information
jasonbosco authored Feb 15, 2025
2 parents 8a6c358 + 1e65565 commit 126c5d8
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.idea
.tmp
.phpunit.result.cache
.env
/composer.lock
phpunit.xml
vendor
33 changes: 24 additions & 9 deletions src/Lib/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Typesense\Lib;

use Http\Client\Common\HttpMethodsClient;
use Http\Client\HttpClient;
use Http\Discovery\Psr17FactoryDiscovery;
use Http\Discovery\Psr18ClientDiscovery;
use Monolog\Handler\StreamHandler;
Expand Down Expand Up @@ -56,9 +57,9 @@ class Configuration
private LoggerInterface $logger;

/**
* @var null|ClientInterface
* @var HttpMethodsClient|ClientInterface|null
*/
private ?ClientInterface $client = null;
private $client = null;

/**
* @var int
Expand Down Expand Up @@ -103,8 +104,18 @@ public function __construct(array $config)
$this->logger = new Logger('typesense');
$this->logger->pushHandler(new StreamHandler('php://stdout', $this->logLevel));

if (true === \array_key_exists('client', $config) && $config['client'] instanceof ClientInterface) {
$this->client = $config['client'];
if (isset($config['client'])) {
if ($config['client'] instanceof HttpMethodsClient || $config['client'] instanceof ClientInterface) {
$this->client = $config['client'];
} elseif ($config['client'] instanceof HttpClient) {
$this->client = new HttpMethodsClient(
$config['client'],
Psr17FactoryDiscovery::findRequestFactory(),
Psr17FactoryDiscovery::findStreamFactory()
);
} else {
throw new ConfigError('Client must implement PSR-18 ClientInterface or Http\Client\HttpClient');
}
}
}

Expand Down Expand Up @@ -216,10 +227,14 @@ public function getLogger(): LoggerInterface
*/
public function getClient(): ClientInterface
{
return new HttpMethodsClient(
$this->client ?? Psr18ClientDiscovery::find(),
Psr17FactoryDiscovery::findRequestFactory(),
Psr17FactoryDiscovery::findStreamFactory(),
);
if ($this->client === null) {
$discoveredClient = Psr18ClientDiscovery::find();
$this->client = new HttpMethodsClient(
$discoveredClient,
Psr17FactoryDiscovery::findRequestFactory(),
Psr17FactoryDiscovery::findStreamFactory()
);
}
return $this->client;
}
}
84 changes: 84 additions & 0 deletions tests/Feature/HttpClientsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

namespace Feature;

use Tests\TestCase;
use Http\Client\Common\HttpMethodsClient;
use Http\Discovery\Psr17FactoryDiscovery;
use Http\Discovery\Psr18ClientDiscovery;
use Typesense\Exceptions\ConfigError;
use Symfony\Component\HttpClient\Psr18Client;
use Typesense\Client;
use \stdClass;

class HttpClientsTest extends TestCase
{
private array $baseConfig;

protected function setUp(): void
{
parent::setUp();
$this->baseConfig = [
'api_key' => $_ENV['TYPESENSE_API_KEY'],
'nodes' => [[
'host' => $_ENV['TYPESENSE_NODE_HOST'],
'port' => $_ENV['TYPESENSE_NODE_PORT'],
'protocol' => $_ENV['TYPESENSE_NODE_PROTOCOL']
]]
];
}

public function testWorksWithDefaultClient(): void
{
$client = new Client($this->baseConfig);
$response = $client->health->retrieve();
$this->assertIsBool($response['ok']);
}

public function testWorksWithPsr18Client(): void
{
$httpClient = new Psr18Client();
$wrappedClient = new HttpMethodsClient(
$httpClient,
Psr17FactoryDiscovery::findRequestFactory(),
Psr17FactoryDiscovery::findStreamFactory()
);

$config = array_merge($this->baseConfig, ['client' => $wrappedClient]);
$client = new Client($config);
$response = $client->health->retrieve();
$this->assertIsBool($response['ok']);
}

public function testWorksWithHttpMethodsClient(): void
{
$httpClient = new HttpMethodsClient(
Psr18ClientDiscovery::find(),
Psr17FactoryDiscovery::findRequestFactory(),
Psr17FactoryDiscovery::findStreamFactory()
);

$config = array_merge($this->baseConfig, ['client' => $httpClient]);

$client = new Client($config);
$response = $client->health->retrieve();
$this->assertIsBool($response['ok']);
}

public function testWorksWithLegacyPsr18Client(): void
{
$httpClient = $this->createMock(\Psr\Http\Client\ClientInterface::class);
$config = array_merge($this->baseConfig, ['client' => $httpClient]);
$client = new Client($config);
$this->assertInstanceOf(Client::class, $client);
}

public function testRejectsInvalidClient(): void
{
$this->expectException(ConfigError::class);
$this->expectExceptionMessage('Client must implement PSR-18 ClientInterface or Http\Client\HttpClient');

$config = array_merge($this->baseConfig, ['client' => new stdClass()]);
new Client($config);
}
}

0 comments on commit 126c5d8

Please sign in to comment.