Reputation: 24116
I created a simple wrapper around shopify's REST api (private application using basic auth) like this using Guzzle:
<?php
namespace App\Services;
use stdClass;
use Exception;
use GuzzleHttp\Client as GuzzleClient;
/**
* Class ShopifyService
* @package App\Services
*/
class ShopifyService
{
/**
* @var array $config
*/
private $config = [];
/**
* @var GuzzleClient$guzzleClient
*/
private $guzzleClient;
/**
* ShopifyService constructor.
*/
public function __construct()
{
$this->config = config('shopify');
}
/**
* @return ShopifyService
*/
public function Retail(): ShopifyService
{
return $this->initGuzzleClient(__FUNCTION__);
}
/**
* @return ShopifyService
*/
public function Trade(): ShopifyService
{
return $this->initGuzzleClient(__FUNCTION__);
}
/**
* @param string $uri
* @return stdClass
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws Exception
*/
public function Get(string $uri): stdClass
{
$this->checkIfGuzzleClientInitiated();;
$result = $this->guzzleClient->request('GET', $uri);
return \GuzzleHttp\json_decode($result->getBody());
}
/**
* @throws Exception
*/
private function checkIfGuzzleClientInitiated(): void
{
if (!$this->guzzleClient) {
throw new Exception('Guzzle Client Not Initiated');
}
}
/**
* @param string $storeName
* @return ShopifyService
*/
private function initGuzzleClient(string $storeName): ShopifyService
{
if (!$this->guzzleClient) {
$this->guzzleClient = new GuzzleClient([
'base_url' => $this->config[$storeName]['baseUrl'],
'auth' => [
$this->config[$storeName]['username'],
$this->config[$storeName]['password'],
],
'timeout' => 30,
]);
}
return $this;
}
}
Where the config/shopify.php
looks like this:
<?php
use Constants\System;
return [
System::STORE_RETAIL => [
'baseUrl' => env('SHOPIFY_API_RETAIL_BASE_URL'),
'username' => env('SHOPIFY_API_RETAIL_USERNAME'),
'password' => env('SHOPIFY_API_RETAIL_PASSWORD'),
],
System::STORE_TRADE => [
'baseUrl' => env('SHOPIFY_API_TRADE_BASE_URL'),
'username' => env('SHOPIFY_API_TRADE_USERNAME'),
'password' => env('SHOPIFY_API_TRADE_PASSWORD'),
],
];
When I use the service like this:
$retailShopifySerice = app()->make(\App\Services\ShopifyService::class);
dd($retailShopifySerice->Retail()->Get('/products/1234567890.json'));
I get the following error:
GuzzleHttp\Exception\RequestException cURL error 3: (see https://curl.haxx.se/libcurl/c/libcurl-errors.html)
As you can see, I am making a simple guzzle http client with default option (for base uri + basic auth) and making subsequent GET request.
This should work in theory, but I can't figure out why it's throwing this error?
I've already verified the config is correct (i.e. it has the values I expect) and tried clearing all the laravel cache also.
Any ideas what might be wrong here?
Upvotes: 0
Views: 5114
Reputation: 24116
I could not get the base_url
option to work with Guzzle\Client
for some reason, so I solved it in a different way:
<?php
namespace App\Services;
use Exception;
use App\DTOs\ShopifyResult;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Exception\GuzzleException;
/**
* Class ShopifyService
* @package App\Services
*/
class ShopifyService
{
const REQUEST_TYPE_GET = 'GET';
const REQUEST_TYPE_POST = 'POST';
const REQUEST_TIMEOUT = 30;
/**
* @var array $shopifyConfig
*/
private $shopifyConfig = [];
/**
* ShopifyService constructor.
*/
public function __construct()
{
$this->shopifyConfig = config('shopify');
}
/**
* @param string $storeName
* @param string $requestUri
* @return ShopifyResult
* @throws GuzzleException
*/
public function Get(string $storeName, string $requestUri): ShopifyResult
{
return $this->guzzleRequest(
self::REQUEST_TYPE_GET,
$storeName,
$requestUri
);
}
/**
* @param string $storeName
* @param string $requestUri
* @param array $requestPayload
* @return ShopifyResult
* @throws GuzzleException
*/
public function Post(string $storeName, string $requestUri, array $requestPayload = []): ShopifyResult
{
return $this->guzzleRequest(
self::REQUEST_TYPE_POST,
$storeName,
$requestUri,
$requestPayload
);
}
/**
* @param string $requestType
* @param string $storeName
* @param $requestUri
* @param array $requestPayload
* @return ShopifyResult
* @throws GuzzleException
* @throws Exception
*/
private function guzzleRequest(string $requestType, string $storeName, $requestUri, array $requestPayload = []): ShopifyResult
{
$this->validateShopifyConfig($storeName);
$guzzleClient = new GuzzleClient();
$requestOptions = [
'auth' => [
$this->shopifyConfig[$storeName]['username'],
$this->shopifyConfig[$storeName]['password']
],
'timeout' => self::REQUEST_TIMEOUT,
];
if (count($requestPayload)) {
$requestOptions['json'] = $requestPayload;
}
$response = $guzzleClient->request(
$requestType,
$this->shopifyConfig[$storeName]['baseUrl'] . $requestUri,
$requestOptions
);
list ($usedApiCall, $totalApiCallAllowed) = explode(
'/',
$response->getHeader('X-Shopify-Shop-Api-Call-Limit')[0]
);
$shopifyResult = new ShopifyResult(
$response->getStatusCode(),
$response->getReasonPhrase(),
((int) $totalApiCallAllowed - (int) $usedApiCall),
\GuzzleHttp\json_decode($response->getBody()->getContents())
);
$guzzleClient = null;
unset($guzzleClient);
return $shopifyResult;
}
/**
* @param string $storeName
* @throws Exception
*/
private function validateShopifyConfig(string $storeName): void
{
if (!array_key_exists($storeName, $this->shopifyConfig)) {
throw new Exception("Invalid shopify store {$storeName}");
}
foreach (['baseUrl', 'username', 'password'] as $configFieldName) {
if (!array_key_exists($configFieldName, $this->shopifyConfig[$storeName])) {
throw new Exception("Shopify config missing {$configFieldName} for store {$storeName}");
}
}
}
}
Upvotes: 1