|
| 1 | +VCR Plugin - Record and Replay Responses |
| 2 | +======================================== |
| 3 | + |
| 4 | +The VCR plugins allow you to record & replay HTTP responses. It's very useful for test purpose (using production-like predictable fixtures and avoid making actual HTTP request). |
| 5 | +You can also use it during your development cycle, when the endpoint you're contacting is not ready yet. |
| 6 | + |
| 7 | +Unlike the :doc:`php-http/mock-client </clients/mock-client>`, where you have to manually define responses, the responses are **automatically** generated from the previously recorded ones. |
| 8 | + |
| 9 | +Install |
| 10 | +------- |
| 11 | + |
| 12 | +.. code-block:: bash |
| 13 | +
|
| 14 | + $ composer require --dev php-http/vcr-plugin |
| 15 | +
|
| 16 | +Usage |
| 17 | +----- |
| 18 | + |
| 19 | +To record or replay a response, you will need two components, a **naming strategy** and a **recorder**. |
| 20 | + |
| 21 | +The naming strategy |
| 22 | +******************* |
| 23 | + |
| 24 | +The naming strategy turn a request into a deterministic and unique identifier. |
| 25 | +The identifier must be safe to use with a filesystem. |
| 26 | +The plugin provide a default naming strategy, the ``PathNamingStrategy``. You can define two options: |
| 27 | + |
| 28 | +* **hash_headers**: the list of header(s) that make the request unique (Ex: 'Authorization'). The name & content of the header will be hashed to generate a unique signature. By default no header is used. |
| 29 | +* **hash_body_methods**: indicate for which request methods the body makes requests distinct. (Default: PUT, POST, PATCH) |
| 30 | + |
| 31 | +This naming strategy will turn a GET request to https://example.org/my-path to the ``example.org_GET_my-path`` name, and optionally add hashes if the request |
| 32 | +contain a header defined in the options, or if the method is not idempotent. |
| 33 | + |
| 34 | +To create your own strategy, you need to create a class implementing ``Http\Client\Plugin\Vcr\NamingStrategy\NamingStrategyInterface``. |
| 35 | + |
| 36 | +The recorder |
| 37 | +************ |
| 38 | + |
| 39 | +The recorder records and replays responses. The plugin provides two recorders: |
| 40 | + |
| 41 | +* ``FilesystemRecorder``: Saves the response on your filesystem using Symfony's `filesystem component`_ and `Guzzle PSR7`_ library. |
| 42 | +* ``InMemoryRecorder``: Saves the response in memory. **Response will be lost at the end of the running process** |
| 43 | + |
| 44 | +To create your own recorder, you need to create a class implementing the following interfaces: |
| 45 | + |
| 46 | +* ``Http\Client\Plugin\Vcr\Recorder\RecorderInterface`` used by the RecordPlugin. |
| 47 | +* ``Http\Client\Plugin\Vcr\Recorder\PlayerInterface`` used by the ReplayPlugin. |
| 48 | + |
| 49 | +The plugins |
| 50 | +*********** |
| 51 | + |
| 52 | +There are two plugins, one to record responses, the other to replay them. |
| 53 | + |
| 54 | +* ``Http\Client\Plugin\Vcr\ReplayPlugin``, use a ``PlayerInterface`` to replay previously recorded responses. |
| 55 | +* ``Http\Client\Plugin\Vcr\RecordPlugin``, use a ``RecorderInterface`` instance to record the responses, |
| 56 | + |
| 57 | +Both plugins add a response header to indicate either under which name the response has been stored (RecordPlugin, ``X-VCR-RECORD`` header), or which response name has been used to replay the request (ReplayPlugin, ``X-VCR-REPLAYED`` header). |
| 58 | + |
| 59 | +If you plan on using both plugins at the same time (Replay or Record), the ``ReplayPlugin`` **must always** come first. |
| 60 | +Please also note that by default, the ``ReplayPlugin`` throws an exception when it cannot replay a request. If you want the plugin to continue the request (possibly to the actual server), set the third constructor argument to ``false`` (See example below). |
| 61 | + |
| 62 | +Example |
| 63 | +******* |
| 64 | + |
| 65 | +.. code-block:: php |
| 66 | +
|
| 67 | + <?php |
| 68 | +
|
| 69 | + use Http\Client\Common\PluginClient; |
| 70 | + use Http\Client\Plugin\Vcr\NamingStrategy\PathNamingStrategy; |
| 71 | + use Http\Client\Plugin\Vcr\Recorder\FilesystemRecorder; |
| 72 | + use Http\Client\Plugin\Vcr\RecordPlugin; |
| 73 | + use Http\Client\Plugin\Vcr\ReplayPlugin; |
| 74 | + use Http\Discovery\HttpClientDiscovery; |
| 75 | +
|
| 76 | + $namingStrategy = new PathNamingStrategy([ |
| 77 | + 'hash_headers' => ['X-Custom-Header'], // None by default |
| 78 | + 'hash_body_methods' => ['POST'], // Default: PUT, POST, PATCH |
| 79 | + ]); |
| 80 | + $recorder = new FilesystemRecorder('some/dir/in/vcs'); // You can use InMemoryRecorder as well |
| 81 | +
|
| 82 | + // To record responses: |
| 83 | + $record = new RecordPlugin($namingStrategy, $recorder); |
| 84 | +
|
| 85 | + // To replay responses: |
| 86 | + // Third argument prevent the plugin from throwing an exception when a request cannot be replayed |
| 87 | + $replay = new ReplayPlugin($namingStrategy, $recorder, false); |
| 88 | +
|
| 89 | + $pluginClient = new PluginClient( |
| 90 | + HttpClientDiscovery::find(), |
| 91 | + [$replay, $record] // Replay should always go first |
| 92 | + ); |
| 93 | +
|
| 94 | + /** @var \Psr\Http\Message\RequestInterface $request */ |
| 95 | + $request = new MyRequest('GET', 'https://httplug.io'); |
| 96 | +
|
| 97 | + // Will be recorded in "some/dir/in/vcs" |
| 98 | + $client->sendRequest($request); |
| 99 | +
|
| 100 | + // Will be replayed from "some/dir/in/vcs" |
| 101 | + $client->sendRequest($request); |
| 102 | +
|
| 103 | +.. _filesystem component: https://symfony.com/doc/current/components/filesystem.html |
| 104 | +.. _Guzzle PSR7: https://github.com/guzzle/psr7 |
0 commit comments