slince / shopify-api-php

:rocket: Shopify API Client for PHP
MIT License
128 stars 47 forks source link

Basic CRUD GET for DiscountCode fails #36

Open shaldev opened 5 years ago

shaldev commented 5 years ago

I'm trying to do a custom get request to the following endpoint: /admin/api/2019-04/discount_codes/lookup.json

$client->get('api/2019-04/discount_codes/lookup', [ 'code' => $query ]);

But I receive an error:

Undefined offset: 1 at .../vendor/slince/shopify-api-php/src/Client.php:338)

I've made the same request using a browser (BasicAuth) and it returns a result. But it does some redirect, maybe this is the problem. Anyone had a similar issue? Thanks.

slince commented 5 years ago

Can you try $client->get('discount_codes/lookup') ?

shaldev commented 5 years ago

I tried that also, same result. Sorry for not mentioning it earlier.

Here is a stack trace:

0 .../vendor/slince/shopify-api-php/src/Client.php(338): Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(8, 'Undefined offse...', '/...', 338, Array)

1 .../vendor/slince/shopify-api-php/src/Client.php(296): Slince\Shopify\Client->sendRequest(Object(GuzzleHttp\Psr7\Request), Array)

2 .../vendor/slince/shopify-api-php/src/Client.php(240): Slince\Shopify\Client->doRequest('GET', 'discount_codes/...', Array)

3 .../app/Services/ShopifyService.php(191): Slince\Shopify\Client->get('discount_codes/...', Array)

shaldev commented 5 years ago

So I found out what is the problem, as the docs say

The discount code's location is returned in the location header, not in the DiscountCode object itself. Depending on your HTTP client, the location of the discount code might follow the location header automatically.

So I'm guessing on the redirect the client is not sending the access token, and that is why we get a script to redirect for authentication. And the exception, cause it can't read html. Maybe this is out of the scope of the SDK.

Here is the code I used to extract the header, which by the way is containing the price rule and coupon ids, which I will use to make another call and get the required data. Sorry for the messy code.


$headers = [];
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL,"https://yourshop.myshopify.com/admin/api/2019-04/discount_codes/lookup.json?code=discount20");
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Shopify-Access-Token:access_token_here']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADERFUNCTION,
    function($curl, $header) use (&$headers)
    {
        $len = strlen($header);
        $header = explode(':', $header, 2);
        if (count($header) < 2) // ignore invalid headers
            return $len;

        $name = strtolower(trim($header[0]));

        //getting the location only
        if ($name !== 'location') {
            return $len;
        }

        if (!array_key_exists($name, $headers))
            $headers[$name] = [trim($header[1])];
        else
            $headers[$name][] = trim($header[1]);

        return $len;
    }
);

$response = curl_exec($ch);
curl_close($ch);
var_dump($headers);
maximzasorin commented 5 years ago

I tried to figure out the problem, and here's what I came up with. In my opinion, the problem is really related to the redirection, but it is related to the fact that the API returns Location header without specifying the type.

For example, we have a request:

GET /admin/discount_codes/lookup?code=TEST

API returns:

303 See Other
Location: /admin/price_rules/38374940405555/discount_codes/2393875330

URL, which is given in Location, has no suffix .json, Guzzle passes on this Location, then API redirects us to /admin/auth/login, where Shopify already return HTML page, but not the answer from API.

Similar to the request:

GET /admin/api/2019-04/discount_codes/lookup?code=TEST

I think this problem would be solved if the request for redirection were to be executed not to:

/admin/price_rules/38374940405555/discount_codes/2393875330

but to:

/admin/price_rules/3837494040555/discount_codes/2393875330.json

In this case, the requested JSON object is returned without additional redirect to /admin/auth/login.

@shaldev Guzzle library is used for HTTP requests and all headers (including X-Shopify-Access-Token) that were sent to the original request, except for some cases, are sent when redirecting. I checked this with the debug option. Also see: https://github.com/guzzle/guzzle/issues/1272#issuecomment-156791437

shaldev commented 5 years ago

Thanks for the detailed answer @maximzasorin Should I close this issue?

slince commented 5 years ago

Keep it, I believe there should be a better solution; I will try to improve the problem later.