gnikyt / basic-shopify-api
一个基于 Guzzle 的 Shopify API 包装器,支持 REST 和 GraphQL。
Requires
- php: >=7.3.0
- ext-json: *
- caseyamcl/guzzle_retry_middleware: ^2.3
- guzzlehttp/guzzle: ^6.5 || ^7.0
Requires (Dev)
- ergebnis/composer-normalize: ^2.8
- friendsofphp/php-cs-fixer: ^3.0
- phpstan/phpstan: ^0.12
- phpunit/phpunit: ^6.2 || ^9.3
- dev-master
- v11.0.0
- 10.0.x-dev
- v10.0.6
- v10.0.5
- v10.0.4
- v10.0.3
- v10.0.2
- v10.0.1
- v10.0.0
- 9.1.x-dev
- v9.1.4
- v9.1.3
- v9.1.2
- v9.1.1
- v9.1.0
- 9.0.x-dev
- v9.0.0
- 8.2.x-dev
- v8.2.0
- 8.1.x-dev
- v8.1.0
- 8.0.x-dev
- v8.0.0
- v7.0.0
- v6.1.3
- v6.1.2
- v6.1.1
- v6.1.0
- v6.0.0
- v5.4.0
- v5.3.3
- v5.3.2
- v5.3.1
- v5.3.0
- v5.1.0
- v5.0.0
- v4.0.2
- v4.0.1
- v4.0.0
- v3.0.3
- v3.0.2
- v3.0.1
- v3.0.0
- v2.0.0
- v1.0.1
- v1.0.0
- dev-feature/per-user-data
This package is auto-updated.
Last update: 2024-09-16 20:01:27 UTC
README
使用 Guzzle 为 Shopify 简单、经过测试的 API 包装器。
它支持 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
。
如果同步为 true(常规 REST 调用)
请求的返回值将是一个包含以下内容的数组
response
完整的 Guzzle 响应对象body
JSON 解码的响应体 (\Gnikyt\BasicShopifyAPI\ResponseAccess 实例)errors
如果检测到任何错误,则返回 true/falseexception
如果错误为 true,则可用异常对象status
HTTP 状态码link
包含先前/下一个分页值的数组,如果可用
注意: request()
将别名到 rest()
。
如果同步为 false(restAsync 调用)
请求的返回值将是一个 Guzzle 承诺,您可以自行处理。
承诺的返回值将是一个包含以下内容的对象
response
完整的 Guzzle 响应对象body
JSON 解码的响应体 (\Gnikyt\BasicShopifyAPI\ResponseAccess 实例)errors
如果检测到任何错误,则返回 true/falseexception
如果错误为 true,则可用异常对象status
HTTP 状态码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' => [...]]);
有效的键是 query
和 json
。
传递额外的请求选项
如果您想将额外的请求选项传递给创建的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 响应对象body
JSON 解码的响应体 (\Gnikyt\BasicShopifyAPI\ResponseAccess 实例)errors
如果有错误或没有,如果有错误则返回错误status
HTTP 状态码
示例查询
$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个点。
要调整默认限制,请使用选项类的 setRestLimit
和 setGraphLimit
。
自定义速率限制
您只需禁用内置的速率限制器,并推送自定义的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
中间件包。
默认情况下,429
、500
和503
错误将重试两次。
对于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
获取。
LICENSE
此项目采用MIT许可发布。
杂项
使用Python?请查看basic_shopify_api。