Drupal - Guzzle settings (base_url, user agent)

There is no need to create your own Client or ClientFactory service.

Because ClientFactory::fromOptions() has

$config = NestedArray::mergeDeep($default_config, Settings::get('http_client_config', []), $config);

You can specify default options to Guzzle for all clients created by Drupal via your settings.php. Core only provides an example of proxy settings, but you could alter the user agent via

$settings['http_client_config']['headers']['User-Agent'] = 'Foobar 1.0';

To create a single client with different options, (which will override settings from both ClientFactory::fromOptions() and settings.php), you can use the factory service directly:

\Drupal::service('http_client_factory')->fromOptions([
  'headers' => ['User-Agent' => 'Foobar 1.0'],
]);

You may add your own factory and corresponding service.

# Service definition in YAML.
services:
 my_module.client:
   class: GuzzleHttp\Client
   factory: my_module.client.factory:get
 my_module.client.factory:
   class: MyModule\ClientFactory

And the corresponding PHP (example).

class ClientFactory {

  /**
   * Return a configured Client object.
   */
  public function get() {
    $config = [
      'base_url' => 'https://example.com',
    ];

    $client = new Client($config);

    return $client;
  }
}

However you can set the URL and Header in the request itself so this is not actually necessary. See Request Options.

$options = [
  'headers' => [
    'User-Agent' => 'Foobar 1.0'
  ]
];
$response = $client->request('GET', 'https://example.com/api/endpoint', $options);

One reason why you might want to use a factory is to inject the ConfigFactory or LoggerFactory to add various options.

However in a unit test it probably makes sense not to call the class from the service container so that you may add the quirky MockHandler (Guzzle developers decided on a non-standard way of mocking because).

$mock = new MockHandler([new Response(200, ['Content-Length' => 0])]);
$options = [
  'handler' => HandlerStack::create($mock)
];
$client = new \GuzzleHttp\Client($options);

My preference is to create the factory class. Add a unit test for the factory class that correctly instantiates, and then add unit tests that create the client class directly if I'm testing a custom client that extends GuzzleHttp\Client.

As suggested by gapple in their answer, you may also forgo creating your own Factory class, and instead use the http_client_factory service provided by Drupal 8 core to create a one-off custom Client via the ClientFactory::fromOptions() method. Or you can add default configuration to your settings.php file under $settings['http_client_config'].

Tags:

8