Latheesan
Latheesan

Reputation: 24116

Laravel Guzzle - cURL error 3: (see https://curl.haxx.se/libcurl/c/libcurl-errors.html)

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

Answers (1)

Latheesan
Latheesan

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

Related Questions