The project is in a healthy, maintained state
User-friendly metafield wrapper around Shopify's GraphQL Admin API with built-in retry, batching, and error handling
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

ShopifyAPI::GraphQL::Metafields

User-friendly metafield wrapper around Shopify's GraphQL Admin API with built-in retry, batching, and error handling.

CI

Installation

bundle add shopify_api-graphql-metafields

If bundler is not being used to manage dependencies:

gem install shopify_api-graphql-metafields

Usage

ShopifyAPI::GraphQL::Metafields supports CRUD operations on Metafields and Metafield Definitions, and supports setting metafields in bulk.

Metafields

Upsert Metafields

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
end

To override the fields returned see Field Selection.

Delete Metafields

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
end

To override the fields returned see Field Selection.

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 }")

Setting Metafields in Bulk

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
end

Note 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.

Deleting Metafields in Bulk

TODO!

If you need this you can use Shopify's Bulk API via ShopifyAPI::GraphQL::Bulk.

Metafield Definitions

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...

Field Selection

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 }")

Why Use This Instead of Shopify's API Client?

  • 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

Development

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.

See Also

  • 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 retry
  • ShopifyAPI::GraphQL::Request - A higher-level wrapper around Tiny with improved exception handling and :snake_case hash key conversion
  • TinyGID - Build Global ID (gid://) URI strings from scalar values

License

The gem is available as open source under the terms of the MIT License.


Made by ScreenStaring