Quantcast
Channel: Issues for Drupal core
Viewing all articles
Browse latest Browse all 292776

Provide an interface for Drupal HTTP ClientFactory service

$
0
0

Problem/Motivation

Sometimes we need a custom HTTP client for some custom services, usually for testing purposes. For example, to provide mocked responses for outgoing HTTP requests in functional tests.

For those cases, Drupal provides http_client_factory service, which can provide http_client with custom options.

But in tests, we usually need to provide a custom HTTP Client, not the original Guzzle class. And we can't do dependency injection here and replace the default class Drupal\Core\Http\ClientFactory with a custom one because it doesn't implement any interface.

Steps to reproduce

1. Create a service that calls some external HTTP API, using an HTTP client from the factory, with custom options.

2. Try to create a test module for functional tests, which overrides the client factory and provides a custom HTTP Client with mocked responses.

You will get an error like this:

TypeError: Argument #1 ($httpClientFactory) must be of type Drupal\Core\Http\ClientFactory, Drupal\my_module_test\TestClientFactory given.

Proposed resolution

The optimal way to resolve this issue is to make Drupal\Core\Http\ClientFactoryInterface and use it as the param type in the service constructors, instead of the Drupal Core class.

With this, we can easily create a custom factory, that implements this interface, and replace the core factory with a custom one.

Also, there is a workaround possible like this:

  /**
   * MyModule constructor.
   *
   * @param \Drupal\Core\Http\ClientFactory|\Drupal\my_module_test\TestClientFactory $httpClientFactory
   *   The HTTP client factory service.
   */
  public function __construct(
    protected \Drupal\Core\Http\ClientFactory|\Drupal\my_module_test\TestClientFactory $httpClientFactory,
  ) {
  }

But this looks pretty ugly because we should not mention test assets in the main code.

So, with the suggested change we can type just an interface like this:

  /**
   * MyModule constructor.
   *
   * @param \Drupal\Core\Http\ClientFactoryInterface $httpClientFactory
   *   The HTTP client factory service.
   */
  public function __construct(
    protected \Drupal\Core\Http\ClientFactoryInterface $httpClientFactory,
  ) {
  }

What do you think about this idea?

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet


Viewing all articles
Browse latest Browse all 292776

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>