Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
395 changes: 205 additions & 190 deletions composer.lock

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion src/Response/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,22 @@ public function toApiException(string $errorMessage, ?string $childClass = null)
}

/**
* Returns a MockApiResponse object from the context and the deserializedBody provided.
* Returns an ApiResponse object from the context by mapping the class specified by className.
*/
public function toApiResponseWithMappedType(?string $className)
{
$responseBody = $this->response->getBody();
if (is_null($className)) {
return $this->toApiResponse($this->getResponseBody());
}
if (!is_object($responseBody)) {
return $this->toApiResponse($responseBody);
}
return $this->toApiResponse($this->jsonHelper->mapClass($responseBody, $className));
}

/**
* Returns an ApiResponse object from the context using the specified deserializedBody.
*/
public function toApiResponse($deserializedBody)
{
Expand Down
68 changes: 50 additions & 18 deletions src/Response/ResponseError.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class ResponseError
*/
private $errors;
private $useApiResponse = false;
private $mapErrorTypes = false;
private $nullOn404 = false;

/**
Expand All @@ -23,51 +24,82 @@ public function addError(string $errorCode, ErrorType $error): void
$this->errors[$errorCode] = $error;
}

/**
* Sets the useApiResponse flag.
*/
public function returnApiResponse(): void
{
$this->useApiResponse = true;
}

/**
* Sets the nullOn404 flag.
* Sets the mapErrorTypes flag.
*/
public function nullOn404(): void
public function mapErrorTypesInApiResponse()
{
$this->nullOn404 = true;
$this->mapErrorTypes = true;
}

private function shouldReturnNull(int $statusCode): bool
/**
* Sets the nullOn404 flag.
*/
public function nullOn404(): void
{
if (!$this->nullOn404) {
return false;
}
if ($statusCode !== 404) {
return false;
}
return true;
$this->nullOn404 = true;
}

/**
* Returns calculated result on failure or throws an exception.
*/
public function getResult(Context $context)
{
if ($this->useApiResponse) {
return $this->getApiResponse($context);
}
$statusCode = $context->getResponse()->getStatusCode();
if ($this->shouldReturnNull($statusCode)) {
if ($this->useApiResponse) {
return $context->toApiResponse(null);
}
return null;
}
if ($this->useApiResponse) {

$errorType = $this->getErrorType($statusCode);
if (empty($errorType)) {
throw $context->toApiException('HTTP Response Not OK');
}

throw $errorType->throwable($context);
}

private function getApiResponse(Context $context)
{
$statusCode = $context->getResponse()->getStatusCode();
if ($this->shouldReturnNull($statusCode)) {
return $context->toApiResponse(null);
}

$errorType = $this->getErrorType($statusCode);
if (!$this->mapErrorTypes || empty($errorType)) {
return $context->toApiResponse($context->getResponseBody());
}

return $context->toApiResponseWithMappedType($errorType->getClassName());
}

private function getErrorType(int $statusCode): ?ErrorType
{
if (isset($this->errors[strval($statusCode)])) {
throw $this->errors[strval($statusCode)]->throwable($context);
return $this->errors[strval($statusCode)];
}
if (isset($this->errors[strval(0)])) {
throw $this->errors[strval(0)]->throwable($context); // throw default error (if set)
return $this->errors[strval(0)];
}
return null;
}

private function shouldReturnNull(int $statusCode): bool
{
if (!$this->nullOn404) {
return false;
}
throw $context->toApiException('HTTP Response Not OK');
return $statusCode === 404;
}
}
9 changes: 9 additions & 0 deletions src/Response/ResponseHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ public function returnApiResponse(): self
return $this;
}

/**
* Map the types for the failure response body in ApiResponse
*/
public function mapErrorTypesInApiResponse(): self
{
$this->responseError->mapErrorTypesInApiResponse();
return $this;
}

/**
* Sets the nullOn404 flag in ResponseError.
*/
Expand Down
10 changes: 9 additions & 1 deletion src/Response/Types/ErrorType.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ private function __construct(string $description, ?string $className, bool $hasE
}

/**
* Throws an Api exception from the context provided.
* Returns a throwable instance of Api exception from the context provided.
*/
public function throwable(Context $context)
{
Expand All @@ -47,6 +47,14 @@ public function throwable(Context $context)
return $context->toApiException($this->description, $this->className);
}

/**
* Returns the class name of the error type.
*/
public function getClassName(): ?string
{
return $this->className;
}

private function updateErrorDescriptionTemplate($response): void
{
if (!$this->hasErrorTemplate) {
Expand Down
81 changes: 81 additions & 0 deletions tests/ApiCallTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Core\Tests\Mocking\Other\MockException;
use Core\Tests\Mocking\Other\MockException1;
use Core\Tests\Mocking\Other\MockException3;
use Core\Tests\Mocking\Other\MockException4;
use Core\Tests\Mocking\Response\MockResponse;
use Core\Tests\Mocking\Types\MockApiResponse;
use Core\Tests\Mocking\Types\MockRequest;
Expand All @@ -36,6 +37,7 @@
class ApiCallTest extends TestCase
{
private const DUMMY_BODY = ['res' => 'This is raw body'];
private const DUMMY_BODY_NATIVE = 'string body';

/**
* @param string $query Just the query path of the url
Expand Down Expand Up @@ -914,6 +916,85 @@ public function testApiResponseWith100()
$this->assertTrue($result->isError());
}

public function testApiResponseWithMappedErrorTypes()
{
$response = new MockResponse();
$response->setStatusCode(400);
$response->setBody(self::DUMMY_BODY);
$context = new Context(MockHelper::getClient()->getGlobalRequest(), $response, MockHelper::getClient());
$result = MockHelper::responseHandler()
->throwErrorOn("400", ErrorType::init('', MockException4::class))
->returnApiResponse()
->mapErrorTypesInApiResponse()
->getResult($context);
$this->assertInstanceOf(MockApiResponse::class, $result);
$this->assertEquals(new MockException4(), $result->getResult());
$this->assertTrue($result->isError());
}

public function testApiResponseWithMappedErrorTypesWithoutClass()
{
$response = new MockResponse();
$response->setStatusCode(400);
$response->setBody(self::DUMMY_BODY);
$context = new Context(MockHelper::getClient()->getGlobalRequest(), $response, MockHelper::getClient());
$result = MockHelper::responseHandler()
->throwErrorOn("400", ErrorType::init(''))
->returnApiResponse()
->mapErrorTypesInApiResponse()
->getResult($context);
$this->assertInstanceOf(MockApiResponse::class, $result);
$this->assertEquals(self::DUMMY_BODY, $result->getResult());
$this->assertTrue($result->isError());
}

public function testApiResponseWithMappedErrorTypesWithoutObjBody()
{
$response = new MockResponse();
$response->setStatusCode(400);
$response->setBody(self::DUMMY_BODY_NATIVE);
$context = new Context(MockHelper::getClient()->getGlobalRequest(), $response, MockHelper::getClient());
$result = MockHelper::responseHandler()
->throwErrorOn("400", ErrorType::init('', MockException4::class))
->returnApiResponse()
->mapErrorTypesInApiResponse()
->getResult($context);
$this->assertInstanceOf(MockApiResponse::class, $result);
$this->assertEquals(self::DUMMY_BODY_NATIVE, $result->getResult());
$this->assertTrue($result->isError());
}

public function testApiResponseWithMappedErrorTypesWithUnknownStatus()
{
$response = new MockResponse();
$response->setStatusCode(100);
$response->setBody(self::DUMMY_BODY);
$context = new Context(MockHelper::getClient()->getGlobalRequest(), $response, MockHelper::getClient());
$result = MockHelper::responseHandler()
->returnApiResponse()
->mapErrorTypesInApiResponse()
->getResult($context);
$this->assertInstanceOf(MockApiResponse::class, $result);
$this->assertEquals(self::DUMMY_BODY, $result->getResult());
$this->assertTrue($result->isError());
}

public function testApiResponseWithMappedErrorTypesWithUnknownStatusGlobal()
{
$response = new MockResponse();
$response->setStatusCode(100);
$response->setBody(self::DUMMY_BODY);
$context = new Context(MockHelper::getClient()->getGlobalRequest(), $response, MockHelper::getClient());
$result = MockHelper::responseHandler()
->throwErrorOn("0", ErrorType::init('', MockException4::class))
->returnApiResponse()
->mapErrorTypesInApiResponse()
->getResult($context);
$this->assertInstanceOf(MockApiResponse::class, $result);
$this->assertEquals(new MockException4(), $result->getResult());
$this->assertTrue($result->isError());
}

public function testApiResponseWithNullOn404()
{
$response = new MockResponse();
Expand Down
11 changes: 11 additions & 0 deletions tests/Mocking/Other/MockException4.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Core\Tests\Mocking\Other;

class MockException4
{
/**
* @var MockClass
*/
public $other1;
}