Skip to content

Commit

Permalink
Refactored endpoints, api and test cases for better usability/stability
Browse files Browse the repository at this point in the history
- Tests are now mockery free.
- Add more tests for Laravel container
  • Loading branch information
pionl committed Oct 2, 2023
1 parent 262d1e3 commit a7d0244
Show file tree
Hide file tree
Showing 31 changed files with 1,152 additions and 583 deletions.
152 changes: 8 additions & 144 deletions src/AbstractApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
use Closure;
use JustSteveKing\UriBuilder\Uri;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use WrkFlow\ApiSdkBuilder\Actions\SendRequestAction;
use WrkFlow\ApiSdkBuilder\Contracts\ApiFactoryContract;
use WrkFlow\ApiSdkBuilder\Endpoints\AbstractEndpoint;
use WrkFlow\ApiSdkBuilder\Environments\AbstractEnvironment;
Expand All @@ -17,8 +15,6 @@
use WrkFlow\ApiSdkBuilder\Exceptions\ServerFailedException;
use WrkFlow\ApiSdkBuilder\Interfaces\ApiInterface;
use WrkFlow\ApiSdkBuilder\Interfaces\EnvironmentOverrideEndpointsInterface;
use WrkFlow\ApiSdkBuilder\Interfaces\OptionsInterface;
use WrkFlow\ApiSdkBuilder\Responses\AbstractResponse;

abstract class AbstractApi implements ApiInterface
{
Expand All @@ -29,25 +25,17 @@ abstract class AbstractApi implements ApiInterface
*/
private array $cachedEndpoints = [];

private ?SendRequestAction $sendRequestAction = null;

/**
* @var array<class-string, class-string<AbstractEndpoint>>
*/
private readonly array $overrideEndpoints;

/**
* @param array<class-string, class-string<AbstractEndpoint>> $overrideEndpoints
*/

public function __construct(
private readonly AbstractEnvironment $environment,
private readonly ApiFactoryContract $factory,
array $overrideEndpoints = []
private readonly ApiFactoryContract $factory
) {
$this->overrideEndpoints = array_merge(
$overrideEndpoints,
$environment instanceof EnvironmentOverrideEndpointsInterface ? $environment->endpoints() : []
);
$this->overrideEndpoints = $environment instanceof EnvironmentOverrideEndpointsInterface ? $environment->endpoints() : [];
}

final public function environment(): AbstractEnvironment
Expand All @@ -67,124 +55,6 @@ final public function uri(): Uri
return $this->environment->uri();
}

final public function get(
string $responseClass,
Uri $uri,
array $headers = [],
?int $expectedResponseStatusCode = null,
Closure $shouldIgnoreLoggersOnError = null,
): AbstractResponse {
$request = $this->factory()
->request()
->createRequest('GET', $uri->toString());

return $this->sendRequestAction()
->execute(
api: $this,
request: $request,
responseClass: $responseClass,
headers: $headers,
expectedResponseStatusCode: $expectedResponseStatusCode,
shouldIgnoreLoggersOnError: $shouldIgnoreLoggersOnError,
);
}

final public function post(
string $responseClass,
Uri $uri,
OptionsInterface|StreamInterface|string $body = null,
array $headers = [],
?int $expectedResponseStatusCode = null,
Closure $shouldIgnoreLoggersOnError = null,
): AbstractResponse {
$request = $this->factory()
->request()
->createRequest('POST', $uri->toString());

return $this->sendRequestAction()
->execute(
api: $this,
request: $request,
responseClass: $responseClass,
body: $body,
headers: $headers,
expectedResponseStatusCode: $expectedResponseStatusCode,
shouldIgnoreLoggersOnError: $shouldIgnoreLoggersOnError,
);
}

final public function put(
string $responseClass,
Uri $uri,
OptionsInterface|StreamInterface|string $body = null,
array $headers = [],
?int $expectedResponseStatusCode = null,
Closure $shouldIgnoreLoggersOnError = null,
): AbstractResponse {
$request = $this->factory()
->request()
->createRequest('PUT', $uri->toString());

return $this->sendRequestAction()
->execute(
api: $this,
request: $request,
responseClass: $responseClass,
body: $body,
headers: $headers,
expectedResponseStatusCode: $expectedResponseStatusCode,
shouldIgnoreLoggersOnError: $shouldIgnoreLoggersOnError,
);
}

final public function delete(
string $responseClass,
Uri $uri,
OptionsInterface|StreamInterface|string $body = null,
array $headers = [],
?int $expectedResponseStatusCode = null,
Closure $shouldIgnoreLoggersOnError = null,
): AbstractResponse {
$request = $this->factory()
->request()
->createRequest('DELETE', $uri->toString());

return $this->sendRequestAction()
->execute(
api: $this,
request: $request,
responseClass: $responseClass,
body: $body,
headers: $headers,
expectedResponseStatusCode: $expectedResponseStatusCode,
shouldIgnoreLoggersOnError: $shouldIgnoreLoggersOnError,
);
}

public function fake(
ResponseInterface $response,
string $responseClass,
Uri $uri,
OptionsInterface|StreamInterface|string $body = null,
array $headers = [],
?int $expectedResponseStatusCode = null,
Closure $shouldIgnoreLoggersOnError = null,
): AbstractResponse {
return $this->sendRequestAction()
->execute(
api: $this,
request: $this->factory()
->request()
->createRequest('FAKE', $uri->toString()),
responseClass: $responseClass,
body: $body,
headers: $headers,
expectedResponseStatusCode: $expectedResponseStatusCode,
fakedResponse: $response,
shouldIgnoreLoggersOnError: $shouldIgnoreLoggersOnError,
);
}

public function createFailedResponseException(int $statusCode, ResponseInterface $response): ResponseException
{
if ($statusCode >= 400 && $statusCode < 500) {
Expand All @@ -194,6 +64,11 @@ public function createFailedResponseException(int $statusCode, ResponseInterface
return new ServerFailedException($response);
}

final public function shouldIgnoreLoggersOnException(): ?Closure
{
return null;
}

/**
* @template T of AbstractEndpoint
*
Expand Down Expand Up @@ -247,15 +122,4 @@ private function getOverrideEndpointClassIfCan(string $endpoint): string

return $endpoint;
}

private function sendRequestAction(): SendRequestAction
{
if ($this->sendRequestAction instanceof SendRequestAction === false) {
$this->sendRequestAction = $this->factory()
->container()
->make(SendRequestAction::class);
}

return $this->sendRequestAction;
}
}
2 changes: 1 addition & 1 deletion src/Actions/MakeApiFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ interface: StreamFactoryInterface::class,
}

/**
* @template T
* @template T of object
*
* @param class-string<T> $interface
* @param Closure():T $create
Expand Down
40 changes: 15 additions & 25 deletions src/Actions/SendRequestAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,25 @@
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Throwable;
use WrkFlow\ApiSdkBuilder\AbstractApi;
use WrkFlow\ApiSdkBuilder\Contracts\SendRequestActionContract;
use WrkFlow\ApiSdkBuilder\Environments\AbstractEnvironment;
use WrkFlow\ApiSdkBuilder\Events\RequestConnectionFailedEvent;
use WrkFlow\ApiSdkBuilder\Events\RequestFailedEvent;
use WrkFlow\ApiSdkBuilder\Events\ResponseReceivedEvent;
use WrkFlow\ApiSdkBuilder\Events\SendingRequestEvent;
use WrkFlow\ApiSdkBuilder\Exceptions\ResponseException;
use WrkFlow\ApiSdkBuilder\Interfaces\ApiInterface;
use WrkFlow\ApiSdkBuilder\Interfaces\EnvironmentFakeResponseInterface;
use WrkFlow\ApiSdkBuilder\Interfaces\HeadersInterface;
use WrkFlow\ApiSdkBuilder\Interfaces\OptionsInterface;
use WrkFlow\ApiSdkBuilder\Log\Entities\LoggerConfigEntity;
use WrkFlow\ApiSdkBuilder\Log\Entities\LoggerFailConfigEntity;
use WrkFlow\ApiSdkBuilder\Log\Interfaces\ApiLoggerInterface;
use WrkFlow\ApiSdkBuilder\Responses\AbstractResponse;

final class SendRequestAction
/**
* @phpstan-import-type IgnoreLoggersOnExceptionClosure from ApiInterface
*/
final class SendRequestAction implements SendRequestActionContract
{
public function __construct(
private readonly BuildHeadersAction $buildHeadersAction,
Expand All @@ -35,20 +37,8 @@ public function __construct(
) {
}

/**
* @template TResponse of AbstractResponse
*
* @param array<int|string,HeadersInterface|string|string[]> $headers
* @param class-string<TResponse> $responseClass
* @param int|null $expectedResponseStatusCode Will raise and failed
* exception if response
* status code is different
* @param Closure(Throwable):array<ApiLoggerInterface>|null $shouldIgnoreLoggersOnError
*
* @return TResponse
*/
public function execute(
AbstractApi $api,
ApiInterface $api,
RequestInterface $request,
string $responseClass,
OptionsInterface|StreamInterface|string|null $body = null,
Expand All @@ -68,7 +58,7 @@ public function execute(
$loggerConfig = $api->factory()
->loggerConfig();

$logger = $this->getLoggerAction->execute(config: $loggerConfig, host: $request->getUri() ->getHost());
$logger = $this->getLoggerAction->execute(config: $loggerConfig, host: $request->getUri()->getHost());

$environment = $api->environment();

Expand Down Expand Up @@ -107,7 +97,7 @@ public function execute(
*/
private function sendRequest(
AbstractEnvironment $environment,
AbstractApi $api,
ApiInterface $api,
?EventDispatcherInterface $dispatcher,
?ApiLoggerInterface $logger,
LoggerConfigEntity $loggerConfig,
Expand Down Expand Up @@ -149,7 +139,7 @@ private function sendRequest(
}

private function withBody(
AbstractApi $api,
ApiInterface $api,
OptionsInterface|StreamInterface|string|null $body,
RequestInterface $request
): RequestInterface {
Expand All @@ -174,16 +164,16 @@ private function getRequestDuration(float $timeStart): float
/**
* @template TResponse of AbstractResponse
*
* @param class-string<TResponse> $responseClass
* @param int|null $expectedResponseStatusCode Will raise and failed
* @param class-string<TResponse> $responseClass
* @param int|null $expectedResponseStatusCode Will raise and failed
* exception if response
* status code is different
* @param Closure(Throwable):array<ApiLoggerInterface>|null $shouldIgnoreLoggersOnError
* @param IgnoreLoggersOnExceptionClosure $shouldIgnoreLoggersOnError
*
* @return TResponse
*/
private function handleResponse(
AbstractApi $api,
ApiInterface $api,
ResponseInterface $response,
?int $expectedResponseStatusCode,
string $responseClass,
Expand Down Expand Up @@ -254,7 +244,7 @@ private function handleResponse(

private function buildRequest(
AbstractEnvironment $environment,
AbstractApi $api,
ApiInterface $api,
array $headers,
RequestInterface $request,
StreamInterface|string|OptionsInterface|null $body
Expand Down
6 changes: 3 additions & 3 deletions src/Contracts/SDKContainerFactoryContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
namespace WrkFlow\ApiSdkBuilder\Contracts;

use Psr\Http\Message\ResponseInterface;
use WrkFlow\ApiSdkBuilder\AbstractApi;
use WrkFlow\ApiSdkBuilder\Endpoints\AbstractEndpoint;
use WrkFlow\ApiSdkBuilder\Interfaces\ApiInterface;
use WrkFlow\ApiSdkBuilder\Responses\AbstractResponse;
use Wrkflow\GetValue\GetValue;

Expand All @@ -19,12 +19,12 @@ interface SDKContainerFactoryContract
*
* @return T
*/
public function makeEndpoint(AbstractApi $api, string $endpointClass): AbstractEndpoint;
public function makeEndpoint(ApiInterface $api, string $endpointClass): AbstractEndpoint;

/**
* Dynamically creates an instance of the given class.
* - Some classes should be cached for performance (as singletons).
* @template T
* @template T of object
*
* @param class-string<T> $class
*
Expand Down
42 changes: 42 additions & 0 deletions src/Contracts/SendRequestActionContract.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace WrkFlow\ApiSdkBuilder\Contracts;

use Closure;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use WrkFlow\ApiSdkBuilder\Interfaces\ApiInterface;
use WrkFlow\ApiSdkBuilder\Interfaces\HeadersInterface;
use WrkFlow\ApiSdkBuilder\Interfaces\OptionsInterface;
use WrkFlow\ApiSdkBuilder\Responses\AbstractResponse;

/**
* @phpstan-import-type IgnoreLoggersOnExceptionClosure from ApiInterface
*/
interface SendRequestActionContract
{
/**
* @template TResponse of AbstractResponse
*
* @param array<int|string,HeadersInterface|string|string[]> $headers
* @param class-string<TResponse> $responseClass
* @param int|null $expectedResponseStatusCode Will raise and failed
* exception if response
* status code is different
* @param IgnoreLoggersOnExceptionClosure $shouldIgnoreLoggersOnError
* @return TResponse
*/
public function execute(
ApiInterface $api,
RequestInterface $request,
string $responseClass,
OptionsInterface|StreamInterface|string|null $body = null,
array $headers = [],
?int $expectedResponseStatusCode = null,
?ResponseInterface $fakedResponse = null,
Closure $shouldIgnoreLoggersOnError = null
): AbstractResponse;
}
Loading

0 comments on commit a7d0244

Please sign in to comment.