How to Save Empty Strings when using Shopify’s Metafields API

Or more accurately… how to get around this limitation

Photo by Markus Spiske on Unsplash

Shopify’s Metafield REST API is an excellent resource for App and Theme developers, but it comes with a notable limitation — empty strings cannot be saved! This post explores this problem and presents two approaches that can be used to solve it.

The Problem

Let’s look at an example. Say that you are building a Shopify App that has an optional “Disclaimer” setting that can be used to display a disclaimer to customers.

Merchants using your App can either fill in the disclaimer’s text input or they can simply leave it empty if they prefer not to show a disclaimer.

From the merchant’s perspective, the option could look like this:

As a developer you want to use the Metafields REST API to store the disclaimer’s text and then use that field in a Liquid template so that it can be displayed to customers. Your Liquid code might look something like this:

{% if shop.metafields.my_app_namespace.disclaimer != blank %}
<p class="disclaimer">
{{ shop.metafields.my_app_namespace.disclaimer }}
</p>
{% endif %}

The problem comes when the merchant decides to remove the disclaimer. If they delete their text from the input and try to save their settings, what will happen?

A metafield can be updated by sending a POST request to the Metafields API along with a JSON body specifying the namespace, key, value, and value_type of the metafield.

POST /admin/api/2020-04/metafields.json
{
"metafield": {
"namespace": "my_app_namespace",
"key": "disclaimer",
"value": "",
"value_type": "string"
}
}

This is the HTTP request that we would normally want to trigger when a user updates the disclaimer text, but when the input is left blank the value will be set to empty string. This will cause Shopify’s API to respond with an error message and the value of the field will not be updated:

{
"errors": {
"value": [
"can't be blank"
]
}
}

Solutions

Here are two ways that you could solve this problem:

  1. Delete the metafield instead of updating it’s value to empty string
  2. Represent empty string with an arbitrary placeholder

#1 — Delete the Metafield

The first option is to simply delete the field when its value is edited to be empty string. This is generally my preferred solution and is the solution that I would expect Shopify to recommend.

This can be done by simply switching the HTTP request method from POST to DELETE (since this is a REST API the endpoint path remains unchanged).

In addition to checking the value before it is posted, you’ll also need to check if it exists when you attempt to fetch it. If it doesn’t exist you can treat it as an empty string.

#2 — Represent Empty String with an Arbitrary Placeholder

If you prefer not to delete the value for some reason, you can substitute empty string with an arbitrary placeholder.

For example, I could say that in my project empty string is represented by the string fL73rgYdBI9NmrG5.

This approach is implemented in a similar way as the delete solution. Check the field value before it is stored, and switch empty string with its placeholder before triggering the POST request. This can be thought of as “packing” a value for storage.

When fetching the field from the API, check if its value matches your placeholder and set it to empty string when appropriate. This can be thought of as “unpacking” a value.

A simple pack and unpack function could be used to achieve this:

const placeholder = 'fL73rgYdBI9NmrG5'// Values to be passed through this immediately before storage
function pack (val) {
return val === '' ? placeholder : val
}
// Values to be passed through this immediately after retrieval
function unpack (val) {
return val === placeholder ? '' : val
}

Software developer and teacher