* @copyright 2015 - 2017 Timothy J. Warren * @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 4.0 * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient */ namespace Aviat\AnimeClient\API; use Amp; use Amp\Artax\{FormBody, Request}; use Aviat\Ion\Json; use InvalidArgumentException; use Psr\Log\LoggerAwareTrait; /** * Wrapper around Artex to make it easier to build API requests */ class APIRequestBuilder { use LoggerAwareTrait; /** * Url prefix for making url requests * @var string */ protected $baseUrl = ''; /** * Url path of the request * @var string */ protected $path = ''; /** * Query string for the request * @var string */ protected $query = ''; /** * Default request headers * @var array */ protected $defaultHeaders = []; /** * Valid HTTP request methos * @var array */ protected $validMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']; /** * The current request * @var \Amp\Promise */ protected $request; /** * Set an authorization header * * @param string $type The type of authorization, eg, basic, bearer, etc. * @param string $value The authorization value * @return self */ public function setAuth(string $type, string $value): self { $authString = ucfirst($type) . ' ' . $value; $this->setHeader('Authorization', $authString); return $this; } /** * Set a basic authentication header * * @param string $username * @param string $password * @return self */ public function setBasicAuth(string $username, string $password): self { $this->setAuth('basic', base64_encode($username . ':' . $password)); return $this; } /** * Set the request body * * @param FormBody|string $body * @return self */ public function setBody($body): self { $this->request->setBody($body); return $this; } /** * Set body as form fields * * @param array $fields Mapping of field names to values * @return self */ public function setFormFields(array $fields): self { $this->setHeader("Content-Type", "application/x-www-form-urlencoded"); $body = (new FormBody)->addFields($fields); $this->setBody($body); return $this; } /** * Set a request header * * @param string $name * @param string $value * @return self */ public function setHeader(string $name, string $value): self { $this->request->setHeader($name, $value); return $this; } /** * Set multiple request headers * * name => value * * @param array $headers * @return self */ public function setHeaders(array $headers): self { foreach ($headers as $name => $value) { $this->setHeader($name, $value); } return $this; } /** * Set the request body * * @param mixed $body * @return self */ public function setJsonBody($body): self { $requestBody = ( ! is_scalar($body)) ? Json::encode($body) : $body; return $this->setBody($requestBody); } /** * Append a query string in array format * * @param array $params * @return self */ public function setQuery(array $params): self { $this->query = http_build_query($params); return $this; } /** * Return the promise for the current request * * @return \Amp\Promise */ public function getFullRequest() { $this->buildUri(); if ($this->logger) { $this->logger->debug('API Request', [ 'request_url' => $this->request->getUri(), 'request_headers' => $this->request->getAllHeaders(), 'request_body' => $this->request->getBody() ]); } return $this->request; } /** * Create a new http request * * @param string $type * @param string $uri * @throws InvalidArgumentException * @return self */ public function newRequest(string $type, string $uri): self { if ( ! in_array($type, $this->validMethods)) { throw new InvalidArgumentException('Invalid HTTP methods'); } $this->resetState(); $this->request ->setMethod($type) ->setProtocol('1.1'); $this->path = $uri; if ( ! empty($this->defaultHeaders)) { $this->setHeaders($this->defaultHeaders); } return $this; } /** * Create the full request url * * @return void */ private function buildUri() { $url = (strpos($this->path, '//') !== FALSE) ? $this->path : $this->baseUrl . $this->path; if ( ! empty($this->query)) { $url .= '?' . $this->query; } $this->request->setUri($url); } /** * Reset the class state for a new request * * @return void */ private function resetState() { $this->path = ''; $this->query = ''; $this->request = new Request(); } }