Skip to content

Commit efce495

Browse files
author
kshitij verma
committed
added graphql api call for private app
1 parent 7e21cb6 commit efce495

File tree

6 files changed

+236
-75
lines changed

6 files changed

+236
-75
lines changed

.idea/.gitignore

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Client.php

Lines changed: 156 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
<?php
22
namespace Shopify;
33

4+
use GuzzleHttp\Exception\RequestException;
45
use Shopify\Common\ClientInterface;
56
use Shopify\Exception\ApiException;
67

78
/**
89
* Class Client
10+
* @package Shopify
911
*/
1012
class Client implements ClientInterface
1113
{
@@ -24,97 +26,109 @@ class Client implements ClientInterface
2426
*/
2527
const SHOPIFY_ACCESS_TOKEN = 'X-Shopify-Access-Token';
2628

29+
/**
30+
* denine response header pagination string
31+
*/
32+
const PAGINATION_STRING = 'Link';
33+
2734
/**
2835
* response header parameter of shopify api limit
2936
*/
30-
const SHOPIFY_API_LIMIT_HEADER = 'http_x_shopify_shop_api_call_limit';
37+
const API_CALL_RATE_LIMIT_HEADER = 'http_x_shopify_shop_api_call_limit';
3138

3239
/**
3340
* define graphQL api call
3441
*/
3542
const GRAPHQL = 'graphql';
3643

3744
/**
38-
* @var string
3945
* Shopify graphql base url
46+
* @var string
4047
*/
4148
protected $graphql_api_url = "https://{shopify_domain}/admin/api/{version}/graphql.json";
4249

4350
/**
44-
* @var string
4551
* Shopify domain name
52+
* @var string
4653
*/
4754
protected $shop;
4855

4956
/**
50-
* @var string
5157
* Shopify api key
58+
* @var string
5259
*/
5360
protected $api_key;
5461

5562
/**
56-
* @var string
5763
* Shopify password for private app
64+
* @var string
5865
*/
5966
protected $password;
6067

6168
/**
62-
* @var string
6369
* Shopify shared secret key for private app
70+
* @var string
6471
*/
6572
protected $shared_secret;
6673

6774
/**
75+
* array('version')
6876
* @var array
69-
* array of version
7077
*/
7178
protected $api_params;
7279

7380
/**
74-
* @var array
7581
* Shopify api call url
82+
* @var array
7683
*/
7784
protected $base_urls;
7885

7986
/**
80-
* @var array
8187
* get api header array according to private and public app
88+
* @var array
8289
*/
8390
protected $requestHeaders;
8491

8592
/**
86-
* @var string
8793
* Shopify api version
94+
* @var string
8895
*/
8996
protected $api_version;
9097

9198
/**
99+
* get response header
92100
* @var string
101+
*/
102+
protected $next_page;
103+
104+
/**
93105
* get response header
106+
* @var string
94107
*/
95-
private $last_response_headers;
108+
protected $prev_page;
96109

97110
/**
98-
*
111+
* static variable to api is going to reach
112+
* @var bool
99113
*/
100-
public function init(){
101-
echo "hello";
102-
}
114+
protected static $wait_next_api_call = false;
103115

104116
/**
117+
* prepare data for rest api request
105118
* @param $method
106-
* @param $query
119+
* @param $path
107120
* @param array $params
108-
* @return mixed|void
121+
* @return array
109122
* @throws ApiException
123+
* @throws ClientException
110124
*/
111125
public function call($method, $path , array $params = [])
112126
{
113127
$url = $this->base_urls[self::REST_API];
114128
$options = [];
115129
$allowed_http_methods = $this->getHttpMethods();
116130
if(!in_array($method, $allowed_http_methods)){
117-
throw new ApiException(implode(",",$allowed_http_methods)." http methods are allowed.");
131+
throw new ApiException(implode(",",$allowed_http_methods)." http methods are allowed.",0);
118132
}
119133
if(isset($this->requestHeaders[self::REST_API]) && is_array($this->requestHeaders[self::REST_API])) {
120134
$options['headers'] = $this->requestHeaders[self::REST_API];
@@ -130,74 +144,176 @@ public function call($method, $path , array $params = [])
130144
return $this->request($method,$url,$options);
131145
}
132146

133-
public function callGraphql($method, $query)
147+
/**
148+
* prepare data for graphql api request
149+
* @param string $query
150+
* @return mixed|void
151+
* @throws ApiException
152+
* @throws ClientException
153+
*/
154+
public function callGraphql($query)
134155
{
135156
$url = $this->base_urls[self::GRAPHQL];
136157
$options = [];
137-
$allowed_http_methods = $this->getHttpMethods();
138-
if(!in_array($method, $allowed_http_methods))
139-
{
140-
throw new ApiException(implode(",",$allowed_http_methods)." http methods are allowed.");
141-
}
142158
if(isset($this->requestHeaders[self::GRAPHQL]) && is_array($this->requestHeaders[self::GRAPHQL])) {
143159
$options['headers'] = $this->requestHeaders[self::GRAPHQL];
144160
}
145-
$options['body'] = json_encode([
146-
'query' => $query,
147-
]);
148-
// var_dump($options);die;
149-
return $this->request($method,$url,$options);
161+
162+
$options['body'] = $query;
163+
if(self::$wait_next_api_call)
164+
{
165+
usleep(1000000 * rand(3, 6));
166+
}
167+
$response = $this->request('POST', $url, $options);
168+
if(isset($response['errors']))
169+
{
170+
$http_bad_request_code = 400;
171+
throw new ApiException(\GuzzleHttp\json_encode($response['errors']),$http_bad_request_code);
172+
}
150173
}
151174

175+
/**
176+
* send http request
177+
* @param string $method
178+
* @param string $url
179+
* @param array $options
180+
* @return array|mixed
181+
* @throws ApiException
182+
*/
152183
public function request($method,$url,array $options)
153184
{
154-
$client = new \GuzzleHttp\Client();
155-
$http_response = $client->request($method, $url, $options);
156-
echo "<pre>";
157-
print_r($http_response->getBody()->getContents());
158-
print_r($http_response->getHeader(self::SHOPIFY_API_LIMIT_HEADER));
159-
print_r($http_response->getStatusCode());
160-
print_r($http_response->getHeaders());
161-
die;
185+
try
186+
{
187+
$client = new \GuzzleHttp\Client();
188+
$http_response = $client->request($method, $url, $options);
189+
$response_content = $http_response->getBody()->getContents();
190+
$response = [];
191+
if (strtoupper($method) === 'GET' && $http_response->getHeaderLine(self::PAGINATION_STRING)) {
192+
$this->next_page = $this->parseLinkString($http_response->getHeaderLine(self::PAGINATION_STRING),'next');
193+
$this->prev_page = $this->parseLinkString($http_response->getHeaderLine(self::PAGINATION_STRING),'previous');
194+
}
195+
196+
$response = \GuzzleHttp\json_decode($response_content,true);
197+
if($http_response->getHeaderLine(self::API_CALL_RATE_LIMIT_HEADER)) {
198+
list($api_call_requested, $api_call_Limit) = explode('/', $http_response->getHeaderLine(self::API_CALL_RATE_LIMIT_HEADER));
199+
static::$wait_next_api_call = $api_call_requested / $api_call_Limit >= 0.8;
200+
}
201+
}
202+
catch (RequestException $e)
203+
{
204+
$json_error = json_decode($e->getResponse()->getBody()->getContents(),true);
205+
if(isset($json_error['errors'])) {
206+
$error_message = $json_error['errors'];
207+
}
208+
else {
209+
$error_message = $e->getResponse()->getBody()->getContents();
210+
}
211+
throw new ApiException($error_message,$e->getCode());
212+
}
213+
return $response;
162214
}
163215

216+
/**
217+
* get previous page_info for any resource(products/orders)
218+
* @return string
219+
*/
220+
public function getPrevPage()
221+
{
222+
return $this->prev_page;
223+
}
164224

165225
/**
226+
* check previous page_info for any resource(products/orders)
227+
* @return string
228+
*/
229+
public function hasPrevPage()
230+
{
231+
return !empty($this->prev_page);
232+
}
233+
234+
/**
235+
* get next page_info for any resource(products/orders)
236+
* @return string
237+
*/
238+
public function getNextPage(){
239+
return $this->next_page;
240+
}
241+
242+
/**
243+
* check next page_info for any resource(products/orders)
244+
* @return string
245+
*/
246+
public function hasNextPage(){
247+
return !empty($this->next_page);
248+
}
249+
250+
/**
251+
* parse header string for previous and next page_info
252+
* @param $pagination_string
253+
* @param $page_link
254+
* @return string
255+
*/
256+
public function parseLinkString($pagination_string,$page_link)
257+
{
258+
$matches = [];
259+
preg_match("/<(.*page_info=([a-z0-9\-]+).*)>; rel=\"?{$page_link}\"?/i", $pagination_string, $matches);
260+
return isset($matches[2]) ? $matches[2] : NULL;
261+
}
262+
263+
264+
/**
265+
* return latest api version
166266
* @return string
167-
* @throws ApiException
168267
*/
169268
public function getApiVersion()
170269
{
171270
return $this->api_version;
172271
}
173272

273+
/**
274+
* set api version
275+
* @param api_version
276+
* Exception for valid value
277+
* @throws ApiException
278+
*/
174279
protected function setApiVersion()
175280
{
176281
$this->api_version = !empty($this->api_params['version'])?$this->api_params['version']:self::SHOPIFY_API_VERSION;
177282
if (!preg_match('/^[0-9]{4}-[0-9]{2}$|^unstable$/', $this->api_version))
178283
{
179-
throw new ApiException('Api Version must be of YYYY-MM or unstable');
284+
throw new ApiException('Api Version must be of YYYY-MM or unstable',0);
180285
}
181286
}
182287

183288
/**
289+
* return allowed http api methods
184290
* @return array
185291
*/
186292
public function getHttpMethods()
187293
{
188294
return ['POST', 'PUT','GET', 'DELETE'];
189295
}
190296

297+
/**
298+
* set shopify domain
299+
* @param $shop
300+
* Exception for invalid shop name
301+
* @throws ApiException
302+
*/
191303
protected function setShop($shop)
192304
{
193305
if (!preg_match('/^[a-zA-Z0-9\-]{3,100}\.myshopify\.(?:com|io)$/', $shop)) {
194306
throw new ApiException(
195-
'Shop name should be 3-100 letters, numbers, or hyphens eg mypetstore.myshopify.com'
307+
'Shop name should be 3-100 letters, numbers, or hyphens eg mypetstore.myshopify.com',0
196308
);
197309
}
198310
$this->shop = $shop;
199311
}
200312

313+
/**
314+
* return shopify domain
315+
* @return string
316+
*/
201317
public function getShop()
202318
{
203319
return $this->shop;

src/Common/ClientInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public function call($method, $path, array $params);
2020
* @param string $query
2121
* @return mixed
2222
*/
23-
public function callGraphql($method, $query);
23+
public function callGraphql($query);
2424

2525
/**
2626
* @param string $method

src/Exception/ApiException.php

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,28 @@
66
*/
77
class ApiException extends \Exception
88
{
9-
/*protected $method;
10-
protected $path;
11-
protected $params;
12-
protected $response_headers;
13-
protected $response;
9+
/**
10+
* @var string
11+
* store error message
12+
*/
13+
protected $message;
1414

15-
function __construct($method, $path, $params, $response_headers, $response)
15+
/**
16+
* ApiException constructor.
17+
* @param $message
18+
* @param $code
19+
*/
20+
function __construct($message,$code)
1621
{
17-
$this->method = $method;
18-
$this->path = $path;
19-
$this->params = $params;
20-
$this->response_headers = $response_headers;
21-
$this->response = $response;
22-
parent::__construct($response_headers['http_status_message'], $response_headers['http_status_code']);
22+
$this->message = $message;
23+
parent::__construct($message, $code);
2324
}
2425

25-
function getMethod() { return $this->method; }
26-
function getPath() { return $this->path; }
27-
function getParams() { return $this->params; }
28-
function getResponseHeaders() { return $this->response_headers; }
29-
function getResponse() { return $this->response; }*/
26+
/**
27+
* @return string
28+
* get error message
29+
*/
30+
function getError() {
31+
return $this->message;
32+
}
3033
}

0 commit comments

Comments
 (0)