ohmybrew/basic-shopify-api

此包已被放弃,不再维护。作者建议使用 https://github.com/osiset/Basic-Shopify-API 包。

一个基本的 Shopify API 包装器,支持 REST 和 GraphQL,由 Guzzle 驱动。

安装: 173 662

依赖项: 2

建议者: 0

安全: 0

星标: 212

观察者: 16

分支: 66

v11.0.0 2022-11-30 20:09 UTC

README

Tests codecov License

一个简单的、经过测试的 Shopify API 包装器,使用 Guzzle。

它支持 Shopify 提供的同步/异步 REST 和 GraphQL API,基本的速率限制和请求重试。

它包含生成安装 URL、授权 URL(离线和按用户)、HMAC 签名验证、调用限制和 API 请求的有用方法。

它与 OAuth 和私有 API 应用程序都兼容。

目录

安装

推荐的安装方法是 通过 composer

composer require gnikyt/basic-shopify-api

用法

公共 API

这假设您已在合作伙伴仪表板中正确设置了您的应用程序,并具有正确的密钥和重定向 URI。

REST(同步)

对于 REST 调用,需要商店域和访问令牌。

use Gnikyt\BasicShopifyAPI\BasicShopifyAPI;
use Gnikyt\BasicShopifyAPI\Options;
use Gnikyt\BasicShopifyAPI\Session;

// Create options for the API
$options = new Options();
$options->setVersion('2020-01');

// Create the client and session
$api = new BasicShopifyAPI($options);
$api->setSession(new Session('example.myshopify.com', 'access-token-here'));

// Now run your requests...
$result = $api->rest(...);

REST(异步)

对于 REST 调用,需要商店域和访问令牌。

use Gnikyt\BasicShopifyAPI\BasicShopifyAPI;
use Gnikyt\BasicShopifyAPI\Options;
use Gnikyt\BasicShopifyAPI\Session;

// Create options for the API
$options = new Options();
$options->setVersion('2020-01');

// Create the client and session
$api = new BasicShopifyAPI($options);
$api->setSession(new Session('example.myshopify.com', 'access-token-here'));

// Now run your requests...
$promise = $api->restAsync(...);
$promise->then(function (array $result) {
  // ...
});

GraphQL(同步)

对于 GraphQL 调用,需要商店域和访问令牌。

use Gnikyt\BasicShopifyAPI\BasicShopifyAPI;
use Gnikyt\BasicShopifyAPI\Options;
use Gnikyt\BasicShopifyAPI\Session;

// Create options for the API
$options = new Options();
$options->setVersion('2020-01');

// Create the client and session
$api = new BasicShopifyAPI($options);
$api->setSession(new Session('example.myshopify.com', 'access-token-here'));

// Now run your requests...
$result = $api->graph(...);

GraphQL(异步)

对于 GraphQL 调用,需要商店域和访问令牌。

use Gnikyt\BasicShopifyAPI\BasicShopifyAPI;
use Gnikyt\BasicShopifyAPI\Options;
use Gnikyt\BasicShopifyAPI\Session;

// Create options for the API
$options = new Options();
$options->setVersion('2020-01');

// Create the client and session
$api = new BasicShopifyAPI($options);
$api->setSession(new Session('example.myshopify.com', 'access-token-here'));

// Now run your requests...
$promise = $api->graphAsync(...);
$promise->then(function (array $result) {
  // ...
});

获取访问权限(离线)

这是默认模式,返回永久令牌。

在获取用户的商店域后,可以使用 getAuthUrl 将其重定向到授权屏幕,例如(基本的 PHP)

// Create options for the API
$options = new Options();
$options->setVersion('2020-01');
$options->setApiKey(env('SHOPIFY_API_KEY'));
$options->setApiSecret(env('SHOPIFY_API_SECRET'));

// Create the client and session
$api = new BasicShopifyAPI($options);
$api->setSession(new Session($_SESSION['shop']));

$code = $_GET['code'];
if (!$code) {
  /**
   * No code, send user to authorize screen
   * Pass your scopes as an array for the first argument
   * Pass your redirect URI as the second argument
   */
  $redirect = $api->getAuthUrl(env('SHOPIFY_API_SCOPES'), env('SHOPIFY_API_REDIRECT_URI'));
  header("Location: {$redirect}");
  exit;
} else {
  // We now have a code, lets grab the access token
  $api->requestAndSetAccess($code);

  // You can now make API calls
  $request = $api->rest('GET', '/admin/shop.json'); // or GraphQL
}

获取访问权限(按用户)

您还可以将授权模式更改为 per-user,如 Shopify 文档中所述 。这将在 Shopify 店铺内的应用程序用户中接收用户信息。收到的令牌将在特定时间过期。

// Create options for the API
$options = new Options();
$options->setVersion('2020-01');
$options->setApiKey(env('SHOPIFY_API_KEY'));
$options->setApiSecret(env('SHOPIFY_API_SECRET'));

// Create the client and session
$api = new BasicShopifyAPI($options);
$api->setSession(new Session($_SESSION['shop']));

$code = $_GET['code'];
if (!$code) {
  /**
   * No code, send user to authorize screen
   * Pass your scopes as an array for the first argument
   * Pass your redirect URI as the second argument
   * Pass your grant mode as the third argument
   */
  $redirect = $api->getAuthUrl(env('SHOPIFY_API_SCOPES'), env('SHOPIFY_API_REDIRECT_URI'), 'per-user');
  header("Location: {$redirect}");
  exit;
} else {
  // We now have a code, lets grab the access object
  $api->requestAndSetAccess($code);

  // You can now make API calls
  $request = $api->rest('GET', '/admin/shop.json'); // or GraphQL
}

验证 HMAC 签名

只需传递一个 GET 参数数组。

// Will return true or false if HMAC signature is good.
$valid = $api->verifyRequest($_GET);

私有API

这假设您已在合作伙伴仪表板中正确设置了您的应用程序,并具有正确的密钥和重定向 URI。

REST

对于REST(同步)调用,需要提供商店域名、API密钥和API密码。

// Create options for the API
$options = new Options();
$options->setType(true); // Makes it private
$options->setVersion('2020-01');
$options->setApiKey(env('SHOPIFY_API_KEY'));
$options->setApiPassword(env('SHOPIFY_API_PASSWORD'));

// Create the client and session
$api = new BasicShopifyAPI($options);
$api->setSession(new Session($_SESSION['shop']));

// Now run your requests...
$result = $api->rest(...);

GraphQL

对于GraphQL调用,需要提供商店域名和API密码。

// Create options for the API
$options = new Options();
$options->setType(true); // Makes it private
$options->setVersion('2020-01');
$options->setApiPassword(env('SHOPIFY_API_PASSWORD'));

// Create the client and session
$api = new BasicShopifyAPI($options);
$api->setSession(new Session($_SESSION['shop']));

// Now run your requests...
$result = $api->graph(...);

发送请求

REST

请求使用Guzzle发送。

$api->rest(string $type, string $path, array $params = null, array $headers = [], bool $sync = true);
// or $api->getRestClient()->request(....);
  • type表示GET、POST、PUT、DELETE等。
  • path表示API路径,例如:/admin/products/1920902.json
  • params表示您希望传递给路径的参数数组,例如:['handle' => 'cool-coat']
  • headers表示您希望随请求发送的自定义头数组,例如:['X-Shopify-Test' => '123']
  • sync表示请求是同步还是异步。

您可以使用别名restAsync来跳过将sync设置为false

如果sync为true(常规REST调用)

请求的返回值将是一个包含以下内容的数组:

  • response完整的Guzzle响应对象
  • bodyJSON解码的响应体(\Gnikyt\BasicShopifyAPI\ResponseAccess实例)
  • errors如果检测到错误,则返回true/false
  • exception如果errors为true,则可获取异常对象
  • statusHTTP状态码
  • link包含前一个/下一个分页值的数组,如果可用

注意request()将别名到rest()

如果sync为false(restAsync调用)

请求的返回值将是一个Guzzle承诺,您可以根据自己的需求处理。

承诺的返回值将是一个包含以下内容的对象:

  • response完整的Guzzle响应对象
  • bodyJSON解码的响应体(\Gnikyt\BasicShopifyAPI\ResponseAccess实例)
  • errors如果检测到错误,则返回true/false
  • exception如果errors为true,则可获取异常对象
  • statusHTTP状态码
  • link包含前一个/下一个分页值的数组,如果可用
$promise = $api->restAsync(...);
$promise->then(function (array $result) {
  // `response` and `body`, etc are available in `$result`.
});
重写请求类型

如果您需要在非GET端点上强制查询字符串,例如,您可以指定类型作为键。

$api->rest('PUT', '/admin/themes/12345/assets.json', ['query' => [...]]);

有效的键是queryjson

传递额外的请求选项

如果您希望向创建的Guzzle客户端传递额外的请求选项,请将它们作为构造函数的第二个参数传递。

// Create options for the API
$options = new Options();
$options->setVersion('2020-01');
// ...
$options->setGuzzleOptions(['connect_timeout' => 3.0]);

// Create the client
$api = new BasicShopifyApi($options);

GraphQL

请求使用Guzzle发送。

$api->graph(string $query, array $variables = []);
  • query表示完整的GraphQL查询
  • variables表示查询中使用的变量(如果有)

请求的返回值将是一个包含以下内容的对象:

  • response完整的Guzzle响应对象
  • bodyJSON解码的响应体(\Gnikyt\BasicShopifyAPI\ResponseAccess实例)
  • errors是否有错误,如果有错误,则返回错误
  • statusHTTP状态码

示例查询

$result = $api->graph('{ shop { product(first: 1) { edges { node { handle, id } } } } }');
echo $result['body']['shop']['products']['edges'][0]['node']['handle']; // test-product
// or echo $result['body']->shop->products->edges[0]->node->handle;

示例突变

$result = $api->graph(
    'mutation collectionCreate($input: CollectionInput!) { collectionCreate(input: $input) { userErrors { field message } collection { id } } }',
    ['input' => ['title' => 'Test Collection']]
);
echo $result['body']['collectionCreate']['collection']['id']; // gid://shopify/Collection/63171592234
// or echo $result['body']->collectionCreate->collection->id;

API版本控制

此库支持请求版本控制,例如

// Create options for the API
$options = new Options();
$options->setVersion('2020-01'); // YYYY-MM or "unstable" is accepted

// Create the client
$api = new BasicShopifyAPI($options);

您可以在任何时间覆盖特定API请求的版本控制,例如

// Create options for the API
$options = new Options();
$options->setVersion('2020-01');

// Create the client
$api = new BasicShopifyAPI($options);
$api->rest('GET', '/admin/api/unstable/shop.json'); // Will ignore "2020-01" version and use "unstable" for this request

速率限制

此库内置了一个基本的速率限制器,它使用usleep在适用的调用之间。

  • 对于REST:确保您每秒不超过默认的2个调用。
  • 对于GraphQL:确保您每秒不超过默认的50个点。

要调整默认限制,请使用选项类中的 setRestLimitsetGraphLimit

自定义速率限制

只需禁用内置的速率限制器,并推送自定义的 Guzzle 中间件。示例

$options = new Options();
// ...
$options->disableRateLimiting();

// ...
$api = new BasicShopifyAPI($options);
$api->addMiddleware(new CustomRateLimiter($api), 'rate:limiting');

page_info / 分页支持

2019-07 API 版本引入了一个新的 Link 头,用于分页(在此处解释)。

如果端点支持 page_info,您可以使用 $response->link 来获取 page_info 值,并在下一次请求中传递。

示例

$response = $api->rest('GET', '/admin/products.json', ['limit' => 5]);
$link = $response['link']['next']; // eyJsYXN0X2lkIjo0MDkw
$link2 = $response['link']['previous']; // dkUIsk00wlskWKl
$response = $api->rest('GET', '/admin/products.json', ['limit' => 5, 'page_info' => $link]);

隔离的 API 调用

您只需初始化一次 API,然后就可以为多个商店使用它。每个实例都将包含在内,以便不会污染其他实例。这对于像后台作业处理这样的任务很有用。

$api->withSession(Session $newSession, Closure $closure);

$this 将绑定到闭包。示例

$api->withSession(new Session('someshop.myshopify.com', 'some-token'), function (): void {
  $request = $this->rest('GET', '/admin/shop.json');
  echo $request['body']['shop']['name']; // Some Shop
});

// $api->rest/graph will not be affected by the above code, it will use previously defined session

重试

此库利用了 caseyamcl/guzzle_retry_middleware 中间件包。

默认情况下,429500503 错误将重试两次。

对于 REST 调用,它将利用 Shopify 的 X-Retry-After 头在重试调用之前等待 x 秒。

当所有重试都用尽后,库的标准响应将返回,您可以在其中处理错误。

要更改监视的状态代码或最大重试次数,请使用选项类中的 setGuzzleOptions

// Create options for the API
$options = new Options();
$options->setVersion('2020-01');
// ...
$options->setGuzzleOptions(
  'max_retry_attempts' => 3, // Was 2
  'retry_on_status'    => [429, 503, 400], // Was 439, 503, 500
);

// Create the client
$api = new BasicShopifyApi($options);

错误

此库通过 Guzzle 内部只捕获 400-500 状态范围内的错误。您能够检查此类错误并获取其响应状态代码和正文。

$call = $api->rest('GET', '/admin/non-existant-route-or-object.json');

if ($call['errors']) {
  echo "Oops! {$call['status']} error";
  var_dump($call['body']);

  // Original exception can be accessed via `$call['exception']`
  // Example, if response body was `{"error": "Not found"}`...
  /// then: `$call['body']` would return "Not Found"
}

中间件

此库利用 Guzzle 中间件进行请求/响应检查和修改。您还可以注入中间件。

$api->addMiddleware([callable]);

请参阅 Guzzle 的中间件文档。此外,您还可以浏览此库的中间件以获取示例。

存储

对于存储当前请求时间、API 限制、请求成本等,使用了一个基本的内存数组存储 Gnikyt\BasicShopifyAPI\Store\Memory

如果您想实现一个更高级的存储,例如使用 Redis 的存储,只需实现 Gnikyt\BasicShopifyAPI\Contracts\StateStorage 并将客户端设置为使用它,示例

$timeStore = new RedisStore();
$limitStore = new RedisStore();

$api = new BasicShopifyAPI($options, $timeStore, $limitStore);

文档

代码文档可在 此处 通过 phpDocumentor 获取,使用 phpdoc -d src -t doc

许可

本项目采用 MIT 许可 发布。

杂项

使用 Python?请查看 basic_shopify_api