Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catching exceptions from Guzzle

I'm trying to catch exceptions from a set of tests I'm running on an API I'm developing and I'm using Guzzle to consume the API methods. I've got the tests wrapped in a try/catch block but it is still throwing unhandled exception errors. Adding an event listener as described in their docs doesn't seem to do anything. I need to be able to retrieve the responses that have HTTP codes of 500, 401, 400, in fact anything that isn't 200 as the system will set the most appropriate code based on the result of the call if it didn't work.

Current code example

foreach($tests as $test){          $client = new Client($api_url);         $client->getEventDispatcher()->addListener('request.error', function(Event $event) {                      if ($event['response']->getStatusCode() == 401) {                 $newResponse = new Response($event['response']->getStatusCode());                 $event['response'] = $newResponse;                 $event->stopPropagation();             }                     });          try {              $client->setDefaultOption('query', $query_string);             $request = $client->get($api_version . $test['method'], array(), isset($test['query'])?$test['query']:array());             // Do something with Guzzle.             $response = $request->send();                displayTest($request, $response);         }         catch (Guzzle\Http\Exception\ClientErrorResponseException $e) {              $req = $e->getRequest();             $resp =$e->getResponse();             displayTest($req,$resp);         }         catch (Guzzle\Http\Exception\ServerErrorResponseException $e) {              $req = $e->getRequest();             $resp =$e->getResponse();             displayTest($req,$resp);         }         catch (Guzzle\Http\Exception\BadResponseException $e) {              $req = $e->getRequest();             $resp =$e->getResponse();             displayTest($req,$resp);         }         catch( Exception $e){             echo "AGH!";         }          unset($client);         $client=null;      } 

Even with the specific catch block for the thrown exception type I am still getting back

Fatal error: Uncaught exception 'Guzzle\Http\Exception\ClientErrorResponseException' with message 'Client error response [status code] 401 [reason phrase] Unauthorized [url] 

and all execution on the page stops, as you'd expect. The addition of the BadResponseException catch allowed me to catch 404s correctly, but this doesn't seem to work for 500 or 401 responses. Can anyone suggest where I am going wrong please.

like image 908
Eric Avatar asked Jul 15 '13 15:07

Eric


People also ask

What is guzzle exception?

A GuzzleHttp\Exception\ConnectException exception is thrown in the event of a networking error. This exception extends from GuzzleHttp\Exception\TransferException . A GuzzleHttp\Exception\ClientException is thrown for 400 level errors if the http_errors request option is set to true.

How do I get guzzle error?

So a simple try-catch on GuzzleHttp\Exception\ClientException and then using getResponse on that exception to see what 400-level error and continuing from there.

How does PHP handle connection refused exception?

You can handle it using try and catch , can't you? Or check your log on which specific exception is thrown when you get connection refused and put that one instead of the Exception in the catch. But Exception is the one that all extend from so that will catch all exceptions.

What is the use of guzzle?

Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and trivial to integrate with web services. Simple interface for building query strings, POST requests, streaming large uploads, streaming large downloads, using HTTP cookies, uploading JSON data, etc...


2 Answers

Depending on your project, disabling exceptions for guzzle might be necessary. Sometimes coding rules disallow exceptions for flow control. You can disable exceptions for Guzzle 3 like this:

$client = new \Guzzle\Http\Client($httpBase, array(   'request.options' => array(      'exceptions' => false,    ) )); 

This does not disable curl exceptions for something like timeouts, but now you can get every status code easily:

$request = $client->get($uri); $response = $request->send(); $statuscode = $response->getStatusCode(); 

To check, if you got a valid code, you can use something like this:

if ($statuscode > 300) {   // Do some error handling } 

... or better handle all expected codes:

if (200 === $statuscode) {   // Do something } elseif (304 === $statuscode) {   // Nothing to do } elseif (404 === $statuscode) {   // Clean up DB or something like this } else {   throw new MyException("Invalid response from api..."); } 

For Guzzle 5.3

$client = new \GuzzleHttp\Client(['defaults' => [ 'exceptions' => false ]] ); 

Thanks to @mika

For Guzzle 6

$client = new \GuzzleHttp\Client(['http_errors' => false]); 
like image 95
Trendfischer Avatar answered Oct 12 '22 22:10

Trendfischer


To catch Guzzle errors you can do something like this:

try {     $response = $client->get('/not_found.xml')->send(); } catch (Guzzle\Http\Exception\BadResponseException $e) {     echo 'Uh oh! ' . $e->getMessage(); } 

... but, to be able to "log" or "resend" your request try something like this:

// Add custom error handling to any request created by this client $client->getEventDispatcher()->addListener(     'request.error',      function(Event $event) {          //write log here ...          if ($event['response']->getStatusCode() == 401) {              // create new token and resend your request...             $newRequest = $event['request']->clone();             $newRequest->setHeader('X-Auth-Header', MyApplication::getNewAuthToken());             $newResponse = $newRequest->send();              // Set the response object of the request without firing more events             $event['response'] = $newResponse;              // You can also change the response and fire the normal chain of             // events by calling $event['request']->setResponse($newResponse);              // Stop other events from firing when you override 401 responses             $event->stopPropagation();         }  }); 

... or if you want to "stop event propagation" you can overridde event listener (with a higher priority than -255) and simply stop event propagation.

$client->getEventDispatcher()->addListener('request.error', function(Event $event) { if ($event['response']->getStatusCode() != 200) {         // Stop other events from firing when you get stytus-code != 200         $event->stopPropagation();     } }); 

thats a good idea to prevent guzzle errors like:

request.CRITICAL: Uncaught PHP Exception Guzzle\Http\Exception\ClientErrorResponseException: "Client error response 

in your application.

like image 40
Dado Avatar answered Oct 12 '22 23:10

Dado