User-friendly metafield wrapper around Shopify's GraphQL Admin API with built-in retry, batching, and error handling.
bundle add shopify_api-graphql-metafieldsIf bundler is not being used to manage dependencies:
gem install shopify_api-graphql-metafieldsShopifyAPI::GraphQL::Metafields supports CRUD operations on Metafields and Metafield Definitions, and supports setting metafields in bulk.
You can upsert a single metafield or multiple metafields:
require "shopify_api/graphql/metafields"
metafields = [
{
:owner_id => "gid://shopify/Product/123",
:namespace => "something",
:key => "foo",
# Not required if there's a metafield definition
:type => "number_integer",
:value => "123"
},
{
:owner_id => "gid://shopify/Shop/123",
:namespace => "whatever",
:key => "bar",
:type => "json",
:value => JSON.dump(:a => 123, :b => "bee")
}
]
mf = ShopifyAPI::GraphQL::Metafields.new(shop, token)
begin
results = mf.set(metafields)
results.each do |result|
# result is a Hash with underscored Symbol keys
p result.slice(:id, :value)
end
rescue ShopifyAPI::GraphQL::Metafields::Error => e
p e
endTo override the fields returned see Field Selection.
metafields = [
{
:owner_id => "gid://shopify/Product/123",
:namespace => "something",
:key => "foo"
},
{
:owner_id => "gid://shopify/Shop/123",
:namespace => "whatever",
:key => "bar"
}
]
mf = ShopifyAPI::GraphQL::Metafields.new(shop, token)
begin
results = mf.delete(metafields)
results.each do |result|
# result is a Hash
p result.slice(:key, :namespace)
end
rescue ShopifyAPI::GraphQL::Metafields::Error => e
p e
endTo override the fields returned see Field Selection.
Use the :fields option to select what fields are returned. This accepts an Array of field names:
mf = ShopifyAPI::GraphQL::Metafields.new(shop, token)
mf.set(metafield, :fields => %w[compare_digest legacy_resource_id description])Or a String containing literal GraphQL fields:
mf.set(metafield, :fields => "legacyResourceId constraints { key }")require "shopify_api/graphql/metafields"
set = ShopifyAPI::GraphQL::Metafields::Batch::Set.new(shop, token)
set << metafield1
set << metafield2
# ...
set << metafield100
begin
result = set.flush!
rescue ShopifyAPI::GraphQL::Metafields::Batch::Error => e
p "Bulk set failed: #{e}"
if e.results.any?
p "We did have _some_ success:"
pp e.results
end
if e.errors.any?
p "We encountered some errors:"
pp e.errors
end
if e.user_errors.any?
p "We encountered some user errors:"
pp e.user_errors
end
endNote that this does not use the Shopify Bulk API. If you want to use the Bulk API for metafields or other operations
see ShopifyAPI::GraphQL::Bulk.
Once #flush! is called worker threads (if needed) will be spawned and metafields will be set 25 at a time, per Shopify's Mutations.metafieldsSet call limit.
You can control the number of threads via the :worker_count option:
set = ShopifyAPI::GraphQL::Metafields::Bulk.new(shop, token, :worker_count => 8)Workers are spawned based on the batch size. If you have 50 metafields only 2 workers will be spawned. If you have 25 or less only no workers are spawned.
The default number of workers is 4.
The return value is an Array of results like one gets with Metafield#set. The indices will align with the input metafields' indices.
A nil value means that position errored.
TODO!
If you need this you can use Shopify's Bulk API via ShopifyAPI::GraphQL::Bulk.
require "shopify_api/graphql/metafields"
dfn = ShopifyAPI::GraphQL::Metafields::Definition.new(shop, token)
result = dfn.create(
:name => "My amaaaazing definition",
:namespace => "sshaw",
:key => "ingredients",
:description => "A product's ingredients",
:type => "multi_line_text_field",
:owner_type => "PRODUCT"
)
id = result.dig(:created_definition, :id)
result = dfn.update(
:namespace => "sshaw",
:key => "ingredients",
:owner_type => "PRODUCT",
:description => "A products SUPER SECRET ingredients"
)
# More CRUD operations...Similar to other metafield operation you can specify the returned fields:
id = { :namespace => "sshaw", :key => "ingredients", :owner_type => "PRODUCT" }
dfn.get(id, :fields => %w[id pinned_position])
# Or, specify a String:
dfn.get(id, :fields => "id pinnedPosition constraints { key value }")- Easy-to-use
- Built-in retry
- Batching
- Lightweight
- You can use :snake_case hash keys
Overall, Shopify's API client is bloated trash that will give you development headaches and long-term maintenance nightmares.
We used to use it, staring way back in 2015, but eventually had to pivot away from their Ruby libraries due to developer frustration and high maintenance cost (and don't get us started on the ShopifyApp gem!@#).
For more information see: Shopify/shopify-api-ruby#1181
Shopify Development Tools is used to import the product fixtures and retrieve values. The sdt executable must be in your path.
A Shopify test store is required. cp .env.template .env and fill-in the values. Requests will be made to the given store. The token needs permission to create metafields and metafield definitions.
- Shopify Dev Tools - Command-line program to assist with the development and/or maintenance of Shopify apps and stores
ShopifyAPI::GraphQL::Tiny- Lightweight, no-nonsense, Shopify GraphQL Admin API client with built-in pagination and retryShopifyAPI::GraphQL::Request- A higher-level wrapper aroundTinywith improved exception handling and:snake_casehash key conversionTinyGID- Build Global ID (gid://) URI strings from scalar values
The gem is available as open source under the terms of the MIT License.
Made by ScreenStaring