Dedicated to the Hydrogen framework, headless commerce, and building custom storefronts using the Storefront API.
I need to filter products by the "available_for_sale" property.
It works perfectly in Postman - results are consistent and exactly as I would expect.
However, when I attempt to recreate the query in PHP, the results are incorrect. Specifically, they include a number of products which have the wrong "available_for_sale" property.
I have tried many different things to rectify the issue - using a raw cURL request to graphQL, changing the query, hardcoding everything, ensuring all of the URL / payload structure is correct, but the same thing happens.
The query I am running is as follows: -
{ products(first: 250, query: "tag:[redacted] AND product_type:[redacted] AND NOT available_for_sale:true", sortKey: TITLE, reverse: true) { edges { node { handle title availableForSale } } } }
This code is slightly more complicated in the production/live environment, but the issue persists regardless.
The above, when run in Postman, provides a payload similar to the following:
The part that is confusing me is there is nothing different between the query I've been running in Postman and the one I've ran in PHP. Yet, the PHP request (multiple servers, using composer package and cURL) returns the same erroneous response: -
I have not tried it locally yet (will write a simple Ruby script in a few minutes) but I am extremely confused as to why it's working perfectly in Postman and not in my PHP scripts. Is it something I have done (or not done)?
Happy to share request payloads in private.
Hey @Richard_Peck,
Can you share request IDs from both the Postman request and the PHP request, or provide some PHP code (in it's simplest form) which isn't filtering correctly?
Scott | Developer Advocate @ Shopify
Good morning, thank you for the reply.
Firstly, I've done some more investigating and it seems that the core problem is the Storefront API seems to be caching its responses. I am not sure why this is causing the available/unavailable filtering to become problematic, but I'd imagine it to be a contributing factor. Other requests are not updating as we've added new products and they are not showing.
The code I have been using to test is as follows: -
// Constants
define('SHOPIFY_API_TOKEN', '*********************');
define('SHOPIFY_API_URL', '*********************');
define('SHOPIFY_API_VERSION', '2023-10');
define('NUM_PRODUCTS', 250);
// Headers
header('Content-Type: application/json');
header("Access-Control-Allow-Origin: *");
///////////////////////////////
///////////////////////////////
// RPECK 05/07/2023
// Use cURL to get the GraphQL data because the Shopify API wrapper returned dodgy results
function graphQL($query, $variables = null) {
// Vars
$data = array();
$data['query'] = $query;
$data['variables'] = $variables;
// Initialize cURL
$curl_init = curl_init();
// Set cURL options
curl_setopt($curl_init, CURLOPT_URL, 'https://' . SHOPIFY_API_URL . '/api/' . SHOPIFY_API_VERSION . '/graphql.json"');
curl_setopt($curl_init, CURLOPT_HTTPHEADER,
array(
'Content-Type: application/json',
'Accept: application/json',
'X-Shopify-Storefront-Access-Token: ' . SHOPIFY_API_TOKEN,
'Cache-Control: no-cache'
)
);
curl_setopt($curl_init, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_init, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($curl_init, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($curl_init, CURLOPT_SSL_VERIFYPEER, true);
// Response
$response = curl_exec($curl_init);
// Close cURL
curl_close($curl_init);
// Return
return $response;
}
$query = '
{
products(first: 250, query: "tag:****** AND product_type:***** AND available_for_sale:true", sortKey: CREATED_AT, reverse: true) {
edges {
node {
handle
title
availableForSale
}
}
}
}
';
$payload = graphQL($query);
echo print_r(json_decode($payload), true);
die();
This code outputs the payload I screenshotted in my initial post.
As you can tell from the comment, I was originally using the Shopify composer package to wrap the API but started testing with cURL once I spotted the issue.
Request ID's: -
Happy to provide further details in private if required.
I'm working on a workaround to this already but it would have been nice to have the fact that the Storefront API is cached mentioned in the documentation.
Just to briefly follow up, the cache seems to have refreshed and both issues I was seeing (incorrect filtering as mentioned here and missing products) has been resolved.
Thus, my question is really about how to trigger a cache refresh on the Storefront API? As it is running through Cloudflare, I suppose it's not possible from the client side?
Thanks for the details! If it's working 100% of the time in Postman it indicates there's not a problem with the Storefront API cache but instead the PHP method is caching somewhere along the way.
Scott | Developer Advocate @ Shopify
If that's the case, why did these people experience exactly the same problem?
Those folks are reporting `accept-language` made a different. Can you compare your Postman request to the PHP requests (including headers)?
Scott | Developer Advocate @ Shopify
Hi,
did you figure out a way to solve this? I have the exact same problem: postman is fine but php gives wrong results
I found that the problem was due to the storefront endpoint being cached.
Postman use different VPS instances to send the requests, whereas I was using a single one. This explained why my requests were "stuck" and theirs weren't.
My solution was to switch to the admin API, which meant I had a limit on the number of objects I could pull through each time. My primary reason for using the storefront API was that it was not rate limited, which they seem to have been able to achieve due to caching it!