Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fixed Guzzle error handling
  • Loading branch information
Sammyjo20 committed May 14, 2023
1 parent 8d53814 commit 3b39bd1
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 10 deletions.
28 changes: 19 additions & 9 deletions src/Http/Senders/GuzzleSender.php
Expand Up @@ -14,6 +14,7 @@
use GuzzleHttp\Client as GuzzleClient;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\TransferException;
use Saloon\Repositories\Body\FormBodyRepository;
Expand Down Expand Up @@ -106,21 +107,23 @@ protected function sendSynchronousRequest(PendingRequest $pendingRequest): Respo

try {
$guzzleResponse = $this->client->send($guzzleRequest, $guzzleRequestOptions);
} catch (TransferException $exception) {
// When the exception wasn't a RequestException, we'll throw a fatal
// exception as this is likely a ConnectException, but it will
// catch any new ones Guzzle release.

if (! $exception instanceof RequestException) {
return $this->createResponse($pendingRequest, $guzzleResponse);
} catch (ConnectException $exception) {
// ConnectException means a network exception has happened, like Guzzle
// not being able to connect to the host.

throw new FatalRequestException($exception, $pendingRequest);
} catch (RequestException $exception) {
// Sometimes, Guzzle will throw a RequestException without a response. This
// means that it was fatal, so we should still throw a fatal request exception.

if (is_null($exception->getResponse())) {
throw new FatalRequestException($exception, $pendingRequest);
}

// Otherwise, we'll create a response.

return $this->createResponse($pendingRequest, $exception->getResponse(), $exception);
}

return $this->createResponse($pendingRequest, $guzzleResponse);
}

/**
Expand Down Expand Up @@ -235,6 +238,13 @@ function (TransferException $guzzleException) use ($pendingRequest) {
throw new FatalRequestException($guzzleException, $pendingRequest);
}

// Sometimes, Guzzle will throw a RequestException without a response. This
// means that it was fatal, so we should still throw a fatal request exception.

if (is_null($guzzleException->getResponse())) {
throw new FatalRequestException($guzzleException, $pendingRequest);
}

// Otherwise we'll create a response to convert into an exception.
// This will run the exception through the exception handlers
// which allows the user to handle their own exceptions.
Expand Down
25 changes: 25 additions & 0 deletions tests/Feature/RequestExceptionTest.php
Expand Up @@ -12,6 +12,7 @@
use Saloon\Tests\Fixtures\Requests\UserRequest;
use Saloon\Tests\Fixtures\Requests\ErrorRequest;
use Saloon\Tests\Fixtures\Connectors\TestConnector;
use Saloon\Exceptions\Request\FatalRequestException;
use Saloon\Tests\Fixtures\Requests\BadResponseRequest;
use Saloon\Tests\Fixtures\Connectors\BadResponseConnector;
use Saloon\Tests\Fixtures\Exceptions\CustomRequestException;
Expand Down Expand Up @@ -244,3 +245,27 @@

expect($responseB->failed())->toBeTrue();
});

test('the sender will throw a FatalRequestException if it cannot connect to a site using synchronous', function (string $url) {
$connector = new TestConnector($url);
$request = new UserRequest();

$this->expectException(FatalRequestException::class);

$response = $connector->send($request);
})->with([
'https://saloon.saloon.test',
'https://saloon.doesnt-exist',
]);

test('the sender will throw a FatalRequestException if it cannot connect to a site using asynchronous', function (string $url) {
$connector = new TestConnector($url);
$request = new UserRequest();

$this->expectException(FatalRequestException::class);

$connector->sendAsync($request)->wait();
})->with([
'https://saloon.saloon.test',
'https://saloon.doesnt-exist',
]);
12 changes: 11 additions & 1 deletion tests/Fixtures/Connectors/TestConnector.php
Expand Up @@ -13,14 +13,24 @@ class TestConnector extends Connector

public bool $unique = false;

/**
* Constructor
*
* @param string|null $url
*/
public function __construct(protected ?string $url = null)
{
//
}

/**
* Define the base url of the api.
*
* @return string
*/
public function resolveBaseUrl(): string
{
return apiUrl();
return $this->url ?? apiUrl();
}

/**
Expand Down

0 comments on commit 3b39bd1

Please sign in to comment.