I have an abstract class Consumer:
abstract class Consumer
{
const API_DOMAIN = 'https://test-api.com/v1/';
private $client = null;
private $credentials = [];
public function __construct(array $credentials)
{
$this->client = new Client(); //This is GuzzleHttp/Client.
$this->credentials = $credentials; // An array
}
abstract protected function getEndpoint();
abstract protected function getHttpMethod();
abstract protected function getParameter();
abstract protected function getHeaders();
abstract protected function getContent();
abstract protected function parseResponse($result);
protected function getUrl()
{
//This has to be fixed to accept an array of parameters: [key => value] format
return implode('/', array_filter([self::API_DOMAIN, $this->getEndpoint(), $this->getParameter()]));
}
public function execute()
{
if (empty($this->credentials))
throw new InvalidCredentialsException();
try {
$response = $this->client->request($this->getHttpMethod(), $this->getUrl(), [
'auth' => $this->credentials,
'form_params' => $this->getContent()
]);
return $this->parseResponse(json_decode($response->getBody()->getContents()));
} catch (\Exception $e) {
throw new ErrorResponseException($e->getMessage(), $e->getCode());
}
}
}
And if I have an endpoint that needs to be accessed via GET I do the following:
class ListAll extends Consumer
{
protected function parseResponse($result)
{
//Collection class from illuminate/support package
//by the creators of Laravel.
$collection = new Collection();
foreach ($result as $item) {
$collection->push(new Server($item));
}
return $collection;
}
public function getEndpoint()
{
return 'users';
}
public function getParameter()
{
return null; //No parameters required.
}
public function getHeaders()
{
return []; //No specific headers is going to be sent.
}
public function getContent()
{
return []; //No content is going to be sent.
}
public function getHttpMethod()
{
return 'GET';
}
}
And the class above is pointing to an endpoint that requires no parameters, headers or content. However if it's a POST request (let's say the endpoint is for creating a user) I must have a set() method for content atleast. So I made a trait:
trait SetContentTrait
{
protected $content = [];
public function setContent($content)
{
$this->content = $content;
}
}
And I'm using it in my Create class:
class Create extends Consumer
{
use SetContentTrait;
protected function parseResponse($result)
{
return new User($result);
}
protected function getEndpoint()
{
return 'users';
}
protected function getHttpMethod()
{
return 'POST';
}
public function getParameter()
{
return null;
}
public function getHeaders()
{
return [];
}
public function getContent()
{
return $this->content;
}
}
Whenever I need to call that API I do the following:
$create = new Create($credentials);
$user = [
'username' => 'Iv',
'password' => 'SOMEHASH',
'email' => '[email protected]'
];
$create->setContent($user);
$user = $create->execute();
So is it a good approach to use traits in this case? Not every endpoint requires parameters, headers and content.