HummingBirdAnimeClient/src/AnimeClient/API/APIRequestBuilder.php

296 lines
5.7 KiB
PHP
Raw Normal View History

<?php declare(strict_types=1);
/**
2017-02-15 16:13:32 -05:00
* Hummingbird Anime List Client
*
2018-08-22 13:48:27 -04:00
* An API client for Kitsu to manage anime and manga watch lists
*
2023-07-13 11:08:05 -04:00
* PHP version 8.1
*
2023-07-13 11:08:05 -04:00
* @copyright 2015 - 2023 Timothy J. Warren <tim@timshome.page>
* @license http://www.opensource.org/licenses/mit-license.html MIT License
2020-12-10 17:06:50 -05:00
* @version 5.2
2023-07-13 11:08:05 -04:00
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\API;
use Amp\Future;
use Amp\Http\Client\Form;
2023-07-13 11:06:52 -04:00
use Amp\Http\Client\{HttpClientBuilder, HttpException, Request};
use Aviat\Ion\Json;
use InvalidArgumentException;
use Psr\Log\LoggerAwareTrait;
use Throwable;
use function Amp\async;
use function Aviat\AnimeClient\getResponse;
use const Aviat\AnimeClient\USER_AGENT;
/**
2020-03-11 16:26:17 -04:00
* Wrapper around Http\Client to make it easier to build API requests
*/
abstract class APIRequestBuilder
{
use LoggerAwareTrait;
/**
* Where to look for GraphQL request files
*/
2021-02-03 09:45:18 -05:00
protected string $filePath = '';
/**
* Url prefix for making url requests
*/
2020-04-10 20:01:46 -04:00
protected string $baseUrl = '';
/**
* Url path of the request
*/
2020-04-10 20:01:46 -04:00
protected string $path = '';
/**
* Query string for the request
*/
2020-04-10 20:01:46 -04:00
protected string $query = '';
/**
* Default request headers
*/
2020-04-10 20:01:46 -04:00
protected array $defaultHeaders = [];
/**
* Valid HTTP request methods
*/
2020-04-10 20:01:46 -04:00
protected array $validMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];
/**
* The current request
*/
2020-04-10 20:01:46 -04:00
protected Request $request;
2018-10-01 10:50:22 -04:00
/**
* Do a basic minimal GET request
*/
public static function simpleRequest(string $uri): Request
{
2020-04-10 20:01:46 -04:00
$request = (new Request($uri));
$request->setHeader('User-Agent', USER_AGENT);
$request->setTcpConnectTimeout(300000);
$request->setTransferTimeout(300000);
2020-04-10 20:01:46 -04:00
return $request;
2018-10-01 10:50:22 -04:00
}
/**
* Set an authorization header
*
* @param string $type The type of authorization, eg, basic, bearer, etc.
* @param string $value The authorization value
*/
public function setAuth(string $type, string $value): self
{
$authString = ucfirst($type) . ' ' . $value;
$this->setHeader('Authorization', $authString);
return $this;
}
/**
* Set a basic authentication header
*/
public function setBasicAuth(string $username, string $password): self
{
$this->setAuth('basic', base64_encode($username . ':' . $password));
return $this;
}
/**
* Set the request body
*/
public function setBody(Form|string $body): self
{
2020-03-11 16:26:17 -04:00
$this->request->setBody($body);
return $this;
}
/**
* Set body as form fields
*
* @param array $fields Mapping of field names to values
*/
public function setFormFields(array $fields): self
{
$body = new Form;
array_walk($fields, fn ($content, $name) => $body->addField($name, $content));
return $this->setBody($body);
}
2018-01-10 16:34:25 -05:00
/**
* Unset a request header
*/
public function unsetHeader(string $name): self
{
2020-03-11 16:26:17 -04:00
$this->request->removeHeader($name);
return $this;
}
/**
* Set a request header
*/
public function setHeader(string $name, ?string $value = NULL): self
{
if ($name === '')
{
return $this;
}
if ($value === NULL)
{
$this->unsetHeader($name);
}
else
{
2020-03-11 16:26:17 -04:00
$this->request->setHeader($name, $value);
}
return $this;
}
/**
* Set multiple request headers
*
* name => value
*/
public function setHeaders(array $headers): self
{
array_walk($headers, fn ($value, $name) => $this->setHeader($name, $value));
return $this;
}
/**
* Set the request body
*/
2021-02-16 14:43:51 -05:00
public function setJsonBody(mixed $body): self
{
$requestBody = (is_string($body))
? $body
: Json::encode($body);
return $this->setBody($requestBody);
}
/**
* Append a query string in array format
*/
public function setQuery(array $params): self
{
$this->query = http_build_query($params);
return $this;
}
/**
* Return the promise for the current request
*
* @throws Throwable
*/
public function getFullRequest(): Request
{
$this->buildUri();
$this->logger?->debug('API Request', [
'request_url' => $this->request->getUri(),
'request_headers' => $this->request->getHeaders(),
'request_body' => $this->request->getBody()
->getContent()
->read(),
]);
return $this->request;
}
2018-01-10 16:34:25 -05:00
/**
* Get the data from the response of the passed request
*
* @throws Throwable
2018-01-10 16:34:25 -05:00
*/
public function getResponseData(Request $request): mixed
2018-01-10 16:34:25 -05:00
{
2018-11-29 11:00:50 -05:00
$response = getResponse($request);
return $response->getBody()->buffer();
2018-01-10 16:34:25 -05:00
}
/**
* Create a new http request
*
2017-02-17 10:55:17 -05:00
* @throws InvalidArgumentException
*/
public function newRequest(string $type, string $uri): self
{
if ( ! in_array($type, $this->validMethods, TRUE))
{
throw new InvalidArgumentException('Invalid HTTP method');
}
2021-02-17 20:02:51 -05:00
$realUrl = (str_contains($uri, '//'))
? $uri
: $this->baseUrl . $uri;
$this->resetState($realUrl, $type);
$this->path = $uri;
// Actually create the full url!
$this->buildUri();
if ( ! empty($this->defaultHeaders))
{
$this->setHeaders($this->defaultHeaders);
}
return $this;
}
/**
* Create the full request url
*/
private function buildUri(): Request
{
2021-02-17 20:02:51 -05:00
$url = (str_contains($this->path, '//'))
? $this->path
: $this->baseUrl . $this->path;
if ( ! empty($this->query))
{
$url .= '?' . $this->query;
}
2020-03-11 16:26:17 -04:00
$this->request->setUri($url);
return $this->request;
}
/**
* Reset the class state for a new request
*/
private function resetState(?string $url, string $type = 'GET'): void
{
$requestUrl = $url ?: $this->baseUrl;
$this->path = '';
$this->query = '';
2020-03-11 16:26:17 -04:00
$this->request = new Request($requestUrl, $type);
$this->request->setInactivityTimeout(300000);
$this->request->setTlsHandshakeTimeout(300000);
2020-03-11 16:26:17 -04:00
$this->request->setTcpConnectTimeout(300000);
$this->request->setTransferTimeout(300000);
}
}