Skip to content

Commit

Permalink
Add Client factories for Guzzle and Symfony
Browse files Browse the repository at this point in the history
Signed-off-by: Kim Pepper <[email protected]>
  • Loading branch information
kimpepper committed Feb 5, 2025
1 parent d35ea28 commit a18f79b
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 151 deletions.
81 changes: 18 additions & 63 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,95 +16,50 @@ openseach-php removes the hard-coded dependency on the [Guzzle HTTP client](http

You can continue to use Guzzle, but will need to configure it as a PSR-18 HTTP Client.

### HTTP Client Auto-Discovery
### PSR-18 HTTP Client Interfaces

opensearch-php 2.x will try and discover and install a PSR HTTP Client using [PHP-HTTP Discovery](https://docs.php-http.org/en/latest/discovery.html)
if one is not explicitly provided.
Starting with `opensearch-php` 2.4.0 you can use any PSR-18 compatible HTTP client.

```php
$transport = (new \OpenSearch\TransportFactory())->create();
$endpointFactory = new \OpenSearch\EndpointFactory();
$client = new Client($transport, $endpointFactory, []);

// Send a request to the 'info' endpoint.
$info = $client->info();
```
To simplify creating a Client, we provide two factories to create PSR-18 HTTP clients
for Guzzle and Symfony HTTP clients.

### Configuring Guzzle HTTP Client in 2.x
### Configuring Guzzle HTTP Client in 2.4.x

To configure Guzzle as a PSR HTTP Client with the similar configuration to opensearch 1.x you can use the following example:

Ensure the Guzzle packages are installed via composer:

```php
$guzzleClient = new \GuzzleHttp\Client([
composer require guzzlehttp/guzzle
```

```php
$client = (new \OpenSearch\GuzzleClientFactory())->create([
'base_uri' => 'https://localhost:9200',
'auth' => ['admin', getenv('OPENSEARCH_PASSWORD')],
'verify' => false,
'retries' => 2,
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'User-Agent' => sprintf('opensearch-php/%s (%s; PHP %s)', \OpenSearch\Client::VERSION, PHP_OS, PHP_VERSION),
]
]);

$guzzleHttpFactory = new \GuzzleHttp\Psr7\HttpFactory();

$serializer = new \OpenSearch\Serializers\SmartSerializer();

$requestFactory = new \OpenSearch\RequestFactory(
$guzzleHttpFactory,
$guzzleHttpFactory,
$guzzleHttpFactory,
$serializer,
);

$transport = (new OpenSearch\TransportFactory())
->setHttpClient($guzzleClient)
->setRequestFactory($requestFactory)
->create();

$endpointFactory = new \OpenSearch\EndpointFactory();
$client = new \OpenSearch\Client($transport, $endpointFactory, []);

// Send a request to the 'info' endpoint.
$info = $client->info();
```

### Configuring Symfony HTTP Client in 2.x
### Configuring Symfony HTTP Client in 2.4.x

You can configure [Symfony HTTP Client](https://symfony.com/doc/current/http_client.html) as a PSR HTTP Client using
the following example:

```php
$symfonyPsr18Client = (new \Symfony\Component\HttpClient\Psr18Client())->withOptions([
composer require symfony/http-client
```

```php
$client = (new \OpenSearch\SymfonyClientFactory())->create([
'base_uri' => 'https://localhost:9200',
'auth_basic' => ['admin', getenv('OPENSEARCH_PASSWORD')],
'verify_peer' => false,
'max_retries' => 2,
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
],
]);

$serializer = new \OpenSearch\Serializers\SmartSerializer();

$requestFactory = new \OpenSearch\RequestFactory(
$symfonyPsr18Client,
$symfonyPsr18Client,
$symfonyPsr18Client,
$serializer,
);

$transport = (new \OpenSearch\TransportFactory())
->setHttpClient($symfonyPsr18Client)
->setRequestFactory($requestFactory)
->create();

$endpointFactory = new \OpenSearch\EndpointFactory();
$client = new \OpenSearch\Client($transport, $endpointFactory, []);

// Send a request to the 'info' endpoint.
$info = $client->info();

```
2 changes: 1 addition & 1 deletion samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Start an OpenSearch instance.

```
docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" -e "OPENSEARCH_INITIAL_ADMIN_PASSWORD=myStrongPassword123!" opensearchproject/opensearch:latest
docker compose up
```

Run sample.
Expand Down
68 changes: 4 additions & 64 deletions samples/index.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
<?php

use GuzzleHttp\Psr7\HttpFactory;
use OpenSearch\Client;
use OpenSearch\EndpointFactory;
use OpenSearch\RequestFactory;
use OpenSearch\Serializers\SmartSerializer;
use OpenSearch\TransportFactory;
use Symfony\Component\HttpClient\Psr18Client;
use OpenSearch\GuzzleClientFactory;
use OpenSearch\SymfonyClientFactory;

/**
* Copyright OpenSearch Contributors
Expand All @@ -15,79 +10,24 @@

require_once __DIR__ . '/vendor/autoload.php';

// Auto-configure by discovery example

$transport = (new TransportFactory())->create();
$endpointFactory = new EndpointFactory();
$client = new Client($transport, $endpointFactory, []);

// Send a request to the 'info' endpoint.
$info = $client->info();

// Guzzle example

$guzzleClient = new \GuzzleHttp\Client([
$client = (new GuzzleClientFactory())->create([
'base_uri' => 'https://localhost:9200',
'auth' => ['admin', getenv('OPENSEARCH_PASSWORD')],
'verify' => false,
'retries' => 2,
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'User-Agent' => sprintf('opensearch-php/%s (%s; PHP %s)', Client::VERSION, PHP_OS, PHP_VERSION),
]
]);

$guzzleHttpFactory = new HttpFactory();

$serializer = new SmartSerializer();

$requestFactory = new RequestFactory(
$guzzleHttpFactory,
$guzzleHttpFactory,
$guzzleHttpFactory,
$serializer,
);

$transport = (new TransportFactory())
->setHttpClient($guzzleClient)
->setRequestFactory($requestFactory)
->create();

$endpointFactory = new EndpointFactory();
$client = new Client($transport, $endpointFactory, []);

// Send a request to the 'info' endpoint.
$info = $client->info();

// Symfony example

$symfonyPsr18Client = (new Psr18Client())->withOptions([
$client = (new SymfonyClientFactory())->create([
'base_uri' => 'https://localhost:9200',
'auth_basic' => ['admin', getenv('OPENSEARCH_PASSWORD')],
'verify_peer' => false,
'max_retries' => 2,
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
],
]);

$serializer = new SmartSerializer();

$requestFactory = new RequestFactory(
$symfonyPsr18Client,
$symfonyPsr18Client,
$symfonyPsr18Client,
$serializer,
);

$transport = (new TransportFactory())
->setHttpClient($symfonyPsr18Client)
->setRequestFactory($requestFactory)
->create();

$client = new Client($transport, $endpointFactory, []);

// Send a request to the 'info' endpoint.
$info = $client->info();
19 changes: 0 additions & 19 deletions src/OpenSearch/ClientFactory.php

This file was deleted.

17 changes: 17 additions & 0 deletions src/OpenSearch/ClientFactoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace OpenSearch;

/**
* Creates an OpenSearch client.
*/
interface ClientFactoryInterface
{
/**
* Creates a new OpenSearch client.
*
* @param array<string,mixed> $options
* The options to use when creating the client. The options are specific to the HTTP client implementation.
*/
public function create(array $options): Client;
}
48 changes: 48 additions & 0 deletions src/OpenSearch/GuzzleClientFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace OpenSearch;

use OpenSearch\HttpClient\GuzzleHttpClientFactory;
use Psr\Log\LoggerInterface;
use GuzzleHttp\Psr7\HttpFactory;
use OpenSearch\Serializers\SmartSerializer;

/**
* Creates an OpenSearch client using Guzzle.
*/
class GuzzleClientFactory implements ClientFactoryInterface
{
public function __construct(
protected int $maxRetries = 0,
protected ?LoggerInterface $logger = null,
) {
}

/**
* @param array<string,mixed> $options
* The Guzzle client options.
*/
public function create(array $options): Client
{
$httpClient = (new GuzzleHttpClientFactory($this->maxRetries, $this->logger))->create($options);
$httpFactory = new HttpFactory();

$serializer = new SmartSerializer();

$requestFactory = new RequestFactory(
$httpFactory,
$httpFactory,
$httpFactory,
$serializer,
);

$transport = (new TransportFactory())
->setHttpClient($httpClient)
->setRequestFactory($requestFactory)
->create();

return new Client($transport, new EndpointFactory($serializer), []);
}
}
3 changes: 1 addition & 2 deletions src/OpenSearch/HttpClient/GuzzleHttpClientFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use OpenSearch\Client;
use Psr\Http\Client\ClientInterface;
use Psr\Log\LoggerInterface;

/**
Expand All @@ -25,7 +24,7 @@ public function __construct(
/**
* {@inheritdoc}
*/
public function create(array $options): ClientInterface
public function create(array $options): GuzzleClient
{
if (!isset($options['base_uri'])) {
throw new \InvalidArgumentException('The base_uri option is required.');
Expand Down
3 changes: 1 addition & 2 deletions src/OpenSearch/HttpClient/SymfonyHttpClientFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace OpenSearch\HttpClient;

use OpenSearch\Client;
use Psr\Http\Client\ClientInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpClient\Psr18Client;
Expand All @@ -25,7 +24,7 @@ public function __construct(
/**
* {@inheritdoc}
*/
public function create(array $options): ClientInterface
public function create(array $options): Psr18Client
{
if (!isset($options['base_uri'])) {
throw new \InvalidArgumentException('The base_uri option is required.');
Expand Down
47 changes: 47 additions & 0 deletions src/OpenSearch/SymfonyClientFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace OpenSearch;

use OpenSearch\HttpClient\SymfonyHttpClientFactory;
use OpenSearch\Serializers\SmartSerializer;
use Psr\Log\LoggerInterface;

/**
* Creates an OpenSearch client using Symfony HTTP Client.
*/
class SymfonyClientFactory implements ClientFactoryInterface
{
public function __construct(
protected int $maxRetries = 0,
protected ?LoggerInterface $logger = null,
) {
}

/**
* Creates a new OpenSearch client using Symfony HTTP Client.
*
* @param array<string,mixed> $options
* The Symfony HTTP Client options.
*/
public function create(array $options): Client
{
$httpClient = (new SymfonyHttpClientFactory($this->maxRetries, $this->logger))->create($options);

$serializer = new SmartSerializer();

$requestFactory = new RequestFactory(
$httpClient,
$httpClient,
$httpClient,
$serializer,
);

$transport = (new TransportFactory())
->setHttpClient($httpClient)
->setRequestFactory($requestFactory)
->create();

$endpointFactory = new EndpointFactory();
return new Client($transport, $endpointFactory, []);
}
}
Loading

0 comments on commit a18f79b

Please sign in to comment.