1================= 2Client Middleware 3================= 4 5Middleware intercepts requests before they are sent over the wire and can be 6used to add functionality to handlers. 7 8Modifying Requests 9------------------ 10 11Let's say you wanted to modify requests before they are sent over the wire 12so that they always add specific headers. This can be accomplished by creating 13a function that accepts a handler and returns a new function that adds the 14composed behavior. 15 16.. code-block:: php 17 18 use GuzzleHttp\Ring\Client\CurlHandler; 19 20 $handler = new CurlHandler(); 21 22 $addHeaderHandler = function (callable $handler, array $headers = []) { 23 return function (array $request) use ($handler, $headers) { 24 // Add our custom headers 25 foreach ($headers as $key => $value) { 26 $request['headers'][$key] = $value; 27 } 28 29 // Send the request using the handler and return the response. 30 return $handler($request); 31 } 32 }; 33 34 // Create a new handler that adds headers to each request. 35 $handler = $addHeaderHandler($handler, [ 36 'X-AddMe' => 'hello', 37 'Authorization' => 'Basic xyz' 38 ]); 39 40 $response = $handler([ 41 'http_method' => 'GET', 42 'headers' => ['Host' => ['httpbin.org']] 43 ]); 44 45Modifying Responses 46------------------- 47 48You can change a response as it's returned from a middleware. Remember that 49responses returned from an handler (including middleware) must implement 50``GuzzleHttp\Ring\Future\FutureArrayInterface``. In order to be a good citizen, 51you should not expect that the responses returned through your middleware will 52be completed synchronously. Instead, you should use the 53``GuzzleHttp\Ring\Core::proxy()`` function to modify the response when the 54underlying promise is resolved. This function is a helper function that makes it 55easy to create a new instance of ``FutureArrayInterface`` that wraps an existing 56``FutureArrayInterface`` object. 57 58Let's say you wanted to add headers to a response as they are returned from 59your middleware, but you want to make sure you aren't causing future 60responses to be dereferenced right away. You can achieve this by modifying the 61incoming request and using the ``Core::proxy`` function. 62 63.. code-block:: php 64 65 use GuzzleHttp\Ring\Core; 66 use GuzzleHttp\Ring\Client\CurlHandler; 67 68 $handler = new CurlHandler(); 69 70 $responseHeaderHandler = function (callable $handler, array $headers) { 71 return function (array $request) use ($handler, $headers) { 72 // Send the request using the wrapped handler. 73 return Core::proxy($handler($request), function ($response) use ($headers) { 74 // Add the headers to the response when it is available. 75 foreach ($headers as $key => $value) { 76 $response['headers'][$key] = (array) $value; 77 } 78 // Note that you can return a regular response array when using 79 // the proxy method. 80 return $response; 81 }); 82 } 83 }; 84 85 // Create a new handler that adds headers to each response. 86 $handler = $responseHeaderHandler($handler, ['X-Header' => 'hello!']); 87 88 $response = $handler([ 89 'http_method' => 'GET', 90 'headers' => ['Host' => ['httpbin.org']] 91 ]); 92 93 assert($response['headers']['X-Header'] == 'hello!'); 94 95Built-In Middleware 96------------------- 97 98RingPHP comes with a few basic client middlewares that modify requests 99and responses. 100 101Streaming Middleware 102~~~~~~~~~~~~~~~~~~~~ 103 104If you want to send all requests with the ``streaming`` option to a specific 105handler but other requests to a different handler, then use the streaming 106middleware. 107 108.. code-block:: php 109 110 use GuzzleHttp\Ring\Client\CurlHandler; 111 use GuzzleHttp\Ring\Client\StreamHandler; 112 use GuzzleHttp\Ring\Client\Middleware; 113 114 $defaultHandler = new CurlHandler(); 115 $streamingHandler = new StreamHandler(); 116 $streamingHandler = Middleware::wrapStreaming( 117 $defaultHandler, 118 $streamingHandler 119 ); 120 121 // Send the request using the streaming handler. 122 $response = $streamingHandler([ 123 'http_method' => 'GET', 124 'headers' => ['Host' => ['www.google.com']], 125 'stream' => true 126 ]); 127 128 // Send the request using the default handler. 129 $response = $streamingHandler([ 130 'http_method' => 'GET', 131 'headers' => ['Host' => ['www.google.com']] 132 ]); 133 134Future Middleware 135~~~~~~~~~~~~~~~~~ 136 137If you want to send all requests with the ``future`` option to a specific 138handler but other requests to a different handler, then use the future 139middleware. 140 141.. code-block:: php 142 143 use GuzzleHttp\Ring\Client\CurlHandler; 144 use GuzzleHttp\Ring\Client\CurlMultiHandler; 145 use GuzzleHttp\Ring\Client\Middleware; 146 147 $defaultHandler = new CurlHandler(); 148 $futureHandler = new CurlMultiHandler(); 149 $futureHandler = Middleware::wrapFuture( 150 $defaultHandler, 151 $futureHandler 152 ); 153 154 // Send the request using the blocking CurlHandler. 155 $response = $futureHandler([ 156 'http_method' => 'GET', 157 'headers' => ['Host' => ['www.google.com']] 158 ]); 159 160 // Send the request using the non-blocking CurlMultiHandler. 161 $response = $futureHandler([ 162 'http_method' => 'GET', 163 'headers' => ['Host' => ['www.google.com']], 164 'future' => true 165 ]); 166