Skip to content
This repository has been archived by the owner on Jan 9, 2021. It is now read-only.

Commit

Permalink
Merge pull request #23 from citilinkru/exception_handler
Browse files Browse the repository at this point in the history
add new feature to handle exceptions without response
  • Loading branch information
liderman authored Aug 17, 2017
2 parents ec668d4 + c2c3926 commit 918fcbe
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 1 deletion.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [1.1.0] - 2017-08-17
### Added
- feature to subscribe to new event "expert_sender_api.request.exception_thrown"
### Changed
- changed empty text of error message to more informative

## [1.0.0] - 2017-08-16
### Added
- phpstan lvl 7 checks
Expand Down
58 changes: 58 additions & 0 deletions src/Event/RequestExceptionThrown.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);

namespace Citilink\ExpertSenderApi\Event;

use Citilink\ExpertSenderApi\RequestInterface;
use GuzzleHttp\Exception\RequestException;
use Symfony\Component\EventDispatcher\Event;

/**
* Event on exception thrown while making request
*
* @author Nikita Sapogov <[email protected]>
*/
class RequestExceptionThrown extends Event
{
/**
* @var RequestInterface Request
*/
private $request;

/**
* @var RequestException $exception
*/
private $exception;

/**
* Constructor
*
* @param RequestInterface $apiRequest Api request
* @param RequestException $exception Thrown exception
*/
public function __construct(RequestInterface $apiRequest, RequestException $exception)
{
$this->request = $apiRequest;
$this->exception = $exception;
}

/**
* Get api request
*
* @return RequestInterface Api request
*/
public function getRequest(): RequestInterface
{
return $this->request;
}

/**
* Get thrown exception
*
* @return RequestException Thrown exception
*/
public function getException(): RequestException
{
return $this->exception;
}
}
32 changes: 31 additions & 1 deletion src/RequestSender.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace Citilink\ExpertSenderApi;

use Citilink\ExpertSenderApi\Enum\HttpMethod;
use Citilink\ExpertSenderApi\Event\RequestExceptionThrown;
use Citilink\ExpertSenderApi\Event\ResponseReceivedEvent;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\RequestException;
Expand Down Expand Up @@ -72,7 +73,36 @@ public function send(RequestInterface $request): ResponseInterface
try {
$httpResponse = $this->httpClient->request($request->getMethod()->getValue(), $request->getUri(), $options);
} catch (RequestException $e) {
$httpResponse = $e->getResponse() !== null ? $e->getResponse() : new \GuzzleHttp\Psr7\Response(400);
$this->eventDispatcher->dispatch(
'expert_sender_api.request.exception_thrown',
new RequestExceptionThrown($request, $e)
);

if ($e->getResponse() !== null) {
$httpResponse = $e->getResponse();
} else {
$errorMessage = sprintf(
'ES API ARTIFICIAL ERROR: "%s":"%s". Please note, that this error '
. 'indicates about exception without response. You can subscribe for '
. '"expert_sender_api.request.exception_thrown" event and get more information about exception',
get_class($e),
$e->getMessage()
);

$xml = '<ApiResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
. ' xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ErrorMessage>
<Code>400</Code>
<Message>' . $errorMessage . '</Message>
</ErrorMessage>
</ApiResponse>';

$httpResponse = new \GuzzleHttp\Psr7\Response(
400,
['Content-Type' => 'text/xml', 'Content-Length' => strlen($xml)],
$xml
);
}
}

$apiResponse = new Response($httpResponse);
Expand Down
58 changes: 58 additions & 0 deletions tests/RequestSenderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
namespace Citilink\ExpertSenderApi\Tests;

use Citilink\ExpertSenderApi\Enum\SubscribersGetRequest\DataOption;
use Citilink\ExpertSenderApi\Event\RequestExceptionThrown;
use Citilink\ExpertSenderApi\Event\ResponseReceivedEvent;
use Citilink\ExpertSenderApi\Model\ErrorMessage;
use Citilink\ExpertSenderApi\Model\SubscribersPostRequest\Identifier;
use Citilink\ExpertSenderApi\Model\SubscribersPostRequest\SubscriberInfo;
use Citilink\ExpertSenderApi\Request\SubscribersGetRequest;
use Citilink\ExpertSenderApi\Request\SubscribersPostRequest;
use Citilink\ExpertSenderApi\RequestSender;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
Expand Down Expand Up @@ -116,4 +119,59 @@ function (ResponseReceivedEvent $event) use (&$receivedEventHasBeenSent) {
Assert::assertEquals(null, $apiResponse->getErrorCode());
Assert::assertCount(0, $apiResponse->getErrorMessages());
}

public function testThrowExceptionWithoutResponse()
{
$mockHandler = new MockHandler(
[
new ConnectException(
'cURL error 28: SSL connection timeout (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)',
new Request('GET', '/Api/Subscribers')
),
]
);

$handler = HandlerStack::create($mockHandler);
$client = new Client(['handler' => $handler]);
$eventDispatcher = new EventDispatcher();
$receivedEventHasBeenSent = false;
$thrownExceptionEventHasBeenSent = false;
$eventDispatcher->addListener(
'expert_sender_api.response.received',
function (ResponseReceivedEvent $event) use (&$receivedEventHasBeenSent) {
$receivedEventHasBeenSent = true;
Assert::assertInstanceOf(ResponseReceivedEvent::class, $event);
}
);

$eventDispatcher->addListener(
'expert_sender_api.request.exception_thrown',
function (RequestExceptionThrown $event) use (&$thrownExceptionEventHasBeenSent) {
$thrownExceptionEventHasBeenSent = true;
Assert::assertInstanceOf(RequestExceptionThrown::class, $event);
Assert::assertNotNull($event->getRequest());
Assert::assertNotNull($event->getException());
}
);

$requestSender = new RequestSender($client, 'api-key', $eventDispatcher);
$response = $requestSender->send(new SubscribersGetRequest('[email protected]', DataOption::SHORT()));

Assert::assertTrue($thrownExceptionEventHasBeenSent);
Assert::assertTrue($receivedEventHasBeenSent);
Assert::assertFalse($response->isOk());
Assert::assertEquals(400, $response->getErrorCode());
$errorMessages = $response->getErrorMessages();
Assert::assertCount(1, $errorMessages);
/** @var ErrorMessage $firstErrorMessage */
$firstErrorMessage = reset($errorMessages);
Assert::assertEquals(
'ES API ARTIFICIAL ERROR: "GuzzleHttp\Exception\ConnectException":"cURL error 28: SSL connection '
. 'timeout (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)". Please note, that this error '
. 'indicates about exception without response. You can subscribe for '
. '"expert_sender_api.request.exception_thrown" event and get more information about exception',
$firstErrorMessage->getMessage()
);
Assert::assertEquals([], $firstErrorMessage->getOptions());
}
}

0 comments on commit 918fcbe

Please sign in to comment.