Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added PreRequestListener #5

Merged
merged 1 commit into from
May 27, 2024
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
116 changes: 91 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,19 +359,66 @@ class YourApi extends Api

### Event Listeners

- [`addPostRequestHandler`](#addpostrequesthandler)
- [`addResponseContentsHandler`](#addresponsecontentshandler)
- [`addPreRequestListener`](#addprerequestlistener)
- [`addPostRequestListener`](#addpostrequestlistener)
- [`addResponseContentsListener`](#addresponsecontentslistener)
- [Event Priority](#event-priority)
- [Event Propagation](#event-propagation)

#### `addPostRequestHandler`
#### `addPreRequestListener`

The `addPostRequestHandler` method is used to add a handler function that is executed after a request has been made.
This handler function can be used to inspect the request and response data that was sent to, and received from, the API.
The `addPreRequestListener` method is used to add a function that is called before a request, and all handled data, has been made.
This event listener will be applied to every API request.

```php
$this->addPostRequestHandler(callable $handler, int $priority = 0): self;
$this->addPreRequestListener(callable $listener, int $priority = 0): self;
```

For example:

```php
use ProgrammatorDev\Api\Api;
use ProgrammatorDev\Api\Event\PreRequestEvent;

class YourApi extends Api
{
public function __construct()
{
// a PreRequestEvent is passed as an argument
$this->addPreRequestListener(function(PreRequestEvent $event) {
$request = $event->getRequest();

if ($request->getMethod() === 'POST') {
// do something for all POST requests
// ...
}
});
}

// ...
}
```

Available event methods:

```php
$this->addPreRequestListener(function(PreRequestEvent $event) {
// get request data
$request = $event->getRequest();
// ...
// set request data
$event->setRequest($request);
});
```

#### `addPostRequestListener`

The `addPostRequestListener` method is used to add a function that is called after a request has been made.
This function can be used to inspect the request and response data that was sent to, and received from, the API.
This event listener will be applied to every API request.

```php
$this->addPostRequestListener(callable $listener, int $priority = 0): self;
```

For example, you can use this event listener to handle API errors:
Expand All @@ -384,13 +431,8 @@ class YourApi extends Api
{
public function __construct()
{
// ...

// a PostRequestEvent is passed as an argument
$this->addPostRequestHandler(function(PostRequestEvent $event) {
// request data is also available
// $request = $event->getRequest();

$this->addPostRequestListener(function(PostRequestEvent $event) {
$response = $event->getResponse();
$statusCode = $response->getStatusCode();

Expand All @@ -410,13 +452,27 @@ class YourApi extends Api
}
```

#### `addResponseContentsHandler`
Available event methods:

```php
$this->addPostRequestListener(function(PostRequestEvent $event) {
// get request data
$request = $event->getRequest();
// get response data
$response = $event->getResponse();
// ...
// set response data
$event->setResponse($response);
});
```

#### `addResponseContentsListener`

The `addResponseContentsHandler` method is used to manipulate the response that was received from the API.
The `addResponseContentsListener` method is used to manipulate the response that was received from the API.
This event listener will be applied to every API request.

```php
$this->addResponseContentsHandler(callable $handler, int $priority = 0): self;
$this->addResponseContentsListener(callable $handler, int $priority = 0): self;
```

For example, if the API responses are JSON strings, you can use this event listener to decode them into arrays:
Expand All @@ -429,10 +485,8 @@ class YourApi extends Api
{
public function __construct()
{
// ...

// a ResponseContentsEvent is passed as an argument
$this->addResponseContentsHandler(function(ResponseContentsEvent $event) {
$this->addResponseContentsListener(function(ResponseContentsEvent $event) {
// get response contents and decode json string into an array
$contents = $event->getContents();
$contents = json_decode($contents, true);
Expand All @@ -453,6 +507,18 @@ class YourApi extends Api
}
```

Available event methods:

```php
$this->addResponseContentsListener(function(ResponseContentsEvent $event) {
// get response body contents data
$contents = $event->getContents();
// ...
// set contents
$event->setContents($contents);
});
```

#### Event Priority

It is possible to add multiple listeners for the same event and set the order in which they will be executed.
Expand All @@ -471,14 +537,14 @@ class YourApi extends Api
// but the second is executed first (higher priority) even though it was added after

// executed last (lower priority)
$this->addResponseContentsHandler(
handler: function(PostRequestEvent $event) { ... },
$this->addResponseContentsListener(
listener: function(PostRequestEvent $event) { ... },
priority: 0
);

// executed first (higher priority)
$this->addResponseContentsHandler(
handler: function(PostRequestEvent $event) { ... },
$this->addResponseContentsListener(
listener: function(PostRequestEvent $event) { ... },
priority: 10
);
}
Expand All @@ -498,13 +564,13 @@ class YourApi extends Api
{
public function __construct()
{
$this->addResponseContentsHandler(function(PostRequestEvent $event) {
$this->addResponseContentsListener(function(PostRequestEvent $event) {
// stop propagation so future listeners of this event will not be called
$event->stopPropagation();
});

// this listener will not be called
$this->addResponseContentsHandler(function(PostRequestEvent $event) {
$this->addResponseContentsListener(function(PostRequestEvent $event) {
// ...
});
}
Expand Down Expand Up @@ -682,7 +748,7 @@ class YourApi extends Api
$pool = new FilesystemAdapter();

// file-based cache adapter with a 1-hour default cache lifetime
$this->setClientBuilder(
$this->setCacheBuilder(
new CacheBuilder(
pool: $pool,
ttl: 3600
Expand Down
37 changes: 28 additions & 9 deletions src/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use ProgrammatorDev\Api\Builder\Listener\CacheLoggerListener;
use ProgrammatorDev\Api\Builder\LoggerBuilder;
use ProgrammatorDev\Api\Event\PostRequestEvent;
use ProgrammatorDev\Api\Event\PreRequestEvent;
use ProgrammatorDev\Api\Event\ResponseContentsEvent;
use ProgrammatorDev\Api\Exception\ConfigException;
use ProgrammatorDev\Api\Helper\StringHelperTrait;
Expand Down Expand Up @@ -67,6 +68,8 @@ public function request(
throw new ConfigException('A base URL must be set.');
}

$this->configurePlugins();

if (!empty($this->queryDefaults)) {
$query = \array_merge($this->queryDefaults, $query);
}
Expand All @@ -75,15 +78,24 @@ public function request(
$headers = \array_merge($this->headerDefaults, $headers);
}

$this->configurePlugins();

$uri = $this->buildUri($path, $query);
$request = $this->buildRequest($method, $uri, $headers, $body);
$request = $this->createRequest($method, $uri, $headers, $body);

// pre request listener
$request = $this->eventDispatcher->dispatch(new PreRequestEvent($request))->getRequest();

// request
$response = $this->clientBuilder->getClient()->sendRequest($request);

$this->eventDispatcher->dispatch(new PostRequestEvent($request, $response));
// post request listener
$response = $this->eventDispatcher->dispatch(new PostRequestEvent($request, $response))->getResponse();

// always rewind the body contents in case it was used in the PostRequestEvent
// otherwise it would return an empty string
$response->getBody()->rewind();
$contents = $response->getBody()->getContents();

// response contents listener
return $this->eventDispatcher->dispatch(new ResponseContentsEvent($contents))->getContents();
}

Expand Down Expand Up @@ -236,16 +248,23 @@ public function setAuthentication(?Authentication $authentication): self
return $this;
}

public function addPostRequestHandler(callable $handler, int $priority = 0): self
public function addPreRequestListener(callable $listener, int $priority = 0): self
{
$this->eventDispatcher->addListener(PreRequestEvent::class, $listener, $priority);

return $this;
}

public function addPostRequestListener(callable $listener, int $priority = 0): self
{
$this->eventDispatcher->addListener(PostRequestEvent::class, $handler, $priority);
$this->eventDispatcher->addListener(PostRequestEvent::class, $listener, $priority);

return $this;
}

public function addResponseContentsHandler(callable $handler, int $priority = 0): self
public function addResponseContentsListener(callable $listener, int $priority = 0): self
{
$this->eventDispatcher->addListener(ResponseContentsEvent::class, $handler, $priority);
$this->eventDispatcher->addListener(ResponseContentsEvent::class, $listener, $priority);

return $this;
}
Expand Down Expand Up @@ -274,7 +293,7 @@ private function buildUri(string $path, array $query = []): string
return $uri;
}

private function buildRequest(
private function createRequest(
string $method,
string $uri,
array $headers = [],
Expand Down
7 changes: 6 additions & 1 deletion src/Event/PostRequestEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class PostRequestEvent extends Event
{
public function __construct(
private readonly RequestInterface $request,
private readonly ResponseInterface $response
private ResponseInterface $response
) {}

public function getRequest(): RequestInterface
Expand All @@ -22,4 +22,9 @@ public function getResponse(): ResponseInterface
{
return $this->response;
}

public function setResponse(ResponseInterface $response): void
{
$this->response = $response;
}
}
23 changes: 23 additions & 0 deletions src/Event/PreRequestEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace ProgrammatorDev\Api\Event;

use Psr\Http\Message\RequestInterface;
use Symfony\Contracts\EventDispatcher\Event;

class PreRequestEvent extends Event
{
public function __construct(
private RequestInterface $request
) {}

public function getRequest(): RequestInterface
{
return $this->request;
}

public function setRequest(RequestInterface $request): void
{
$this->request = $request;
}
}
9 changes: 3 additions & 6 deletions src/Event/ResponseContentsEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@

class ResponseContentsEvent extends Event
{
private mixed $contents;

public function __construct($contents)
{
$this->contents = $contents;
}
public function __construct(
private mixed $contents
) {}

public function getContents(): mixed
{
Expand Down
Loading
Loading