It’s Postman.
Hey folks! I want to start off by echoing @Liam-Shopify here - we truly appreciate all the feedback and suggestions. We care deeply about our GQL API and strive for it to be the canonical example for performance and DX. We’ve made a bunch of improvements over the last year (Dev Assistant, enhanced docs, improvements to rate limits / query filters), but as this thread shows, we still have a ways to go.
Extremely difficult to build reusable functions that work with different types of data since the nodes (field names) vary widely. Many calls that are made to products, pages, articles and collections must be built totally separately.
Field names are different, missing and/or lacking coherent SYMMETRY and logic (with the rest api, and between end points WITHIN the graph api).
I was forced to build a “bridge” module to combine data from Rest and Graph (ie. body_html -><-- descriptionHtml). It is also a requirement to build a type of module that converts Graph data (particularly property names) to Rest data.
One of the constant trade offs we face is evolving the API to reflect our learnings while limiting breaking changes. When the GraphQL API was first introduced, we used it as a way to clean up the DX and and make the API more intuitive. However, this has led to further divergence between the REST and GQL APIs over the years, making migration a challenge.
We anticipated this, and have been investing in tooling to ease that transition from REST to GQL. In the REST documentation, we’ve mapped each of the fields to their GQL equivalents, and we’ve trained the Dev Assistant to convert REST APIs to GraphQL. If anyone has suggestions on how we can further simplify migration, we’re all ears!
The requirements of edges vs nodes vs node (or no explicit node) is beyond comprehension and can only be figured out by running specific tests.
Using Graph field naming as the new ground truth is highly problematic because it lacks consistency across different end points, unlike the Rest Api.
I think you will need to use GraphQL Fragments
Conditionals are definitely interesting. These concepts should be more easily found in the docs!
While we do document a lot of these concepts (connection edges, aliasing, fragments), I agree that they’re widely dispersed and hard to find.
I’ve flagged this to the relevant teams - we will work on better documenting these capabilities and making them more easily discoverable.
There are solutions that are possible using the Rest Api which are not possible with the Graph Api - and some may be possible but the workarounds are insane (such as the productsCount issue).
GraphQL and RestAPI are not at feature parity.
Agreed that the lack of parity for counts is disappointing. We have a team working on this, and we’re hoping to have a solution ready for the 2025-04 API release. To provide some context on why this is challenging - it is extremely complex to do count queries with dynamic filters at Shopify scale performantly. In the meantime, I’m not sure if this will suffice for your use case, but we did release an update to allow uncapped exact counts for products without filtering.
If there are other areas where you feel feature parity is lacking, please let us know. We attempted to address all known gaps before announcing REST as legacy, but there may be a few that slipped through the cracks.
The Graphql documentation is also poorly written compared to the Rest Api.
it says to use “originalSource” when updating an image. This is not correct, the actual field to use is “previewImageSource”. Your staff was made aware of this already and apparently its nobodys job to update the docs.
Could you share a code snippet of the specific mutation you were attempting? This will help me better understand the issue.
Additionally, if y’all have other examples where you feel the documentation quality is lacking, do share. We want to make sure the docs are clear and easy to use.
@Darius-Shopify Thanks for taking the time to consider my post. It’s not my intention to attack GraphQl needlessly.
Here’s a few issues that’s preventing me from moving over to Graph for Products (not sure if it’s all them):
- It is not clear on how to set the ‘Position’ of an image using GraphQl. It also does not return a Position key either so is the position only known from the order in the array?
- It is not possible to retrieve the created_at and updated_at fields for product images when you fetch them with the product. Is the workaround to look up each image with the Files endpoint?
- On the rest, product images are a mix of ProductImage and MediaImage types. ProductImage type is not recognized in Graph. Looks like the older product images are coming up as ProductImage. Is this happening on Graph too, I have not been able to thoroughly investigate.
- Rest api product images return variant_ids array field. This is very useful, otherwise we need to pull all variants and match up the image id with the image connected to the variant. Fortunately, the products/images.json endpoint isn’t on the chopping block… right?
- Getting presentment prices (for different currencies) using the GraphQl is very difficult to understand. Just one look at it made me turn back and use Rest.
- For apps that need to process over 100 Variants if they exist, it seems feasible to simply use the Rest api to pull a product, and if it has 100 Variants, we can use the GraphQl api to pull all the variants, so it doesn’t seem to necessitate forcing us to use the GraphQl api to work with the new product model. My app doesn’t update variants, but it might attach a photo to one, if it needs to replace a photo with a different filename. This is very easy to do in Rest.
Issues related to getting me to use Graph for other page types, such as Articles, Pages, and Collections:
- All of my code is built around Symmetry and in the Rest graph, these pages are more or less the same, so its easy to use the same functions to update them. I dug around the Graphql docs for these, and I can write 15,000 characters about how its all a big mess when they are each compared to one another.
Benefits of using Graph for Products:
I started using the GraphQL Api to Update Product data - and the one benefit is that the Rest would reject some updates do to some ‘Inventory/shipping policy something’ nonsense error. There was a thread about it in the old forum. Never solved on Rest, but looks like Graph doesn’t have this issue, so at least that’s one less error.
My app processes 45 stores simultaneously in the background making 100s of calls per second, constantly, so its not fun at all to have to try new ways of doing things that already work, and then discovering all the new headaches from this new way. Better to focus time on new features, not re-working a backend that already works, you know what I mean?
Maybe some specialized team can reach out to partners still using Rest and ask them the exact pain points of switching, and working together to work out all the kinks before applying force. Successful partners are as dedicated to the prosperity of Shopify as anybody!
Cheers
Adding a link here to this recent blog post by @Daniel_Ablestar that describes some of his techniques for efficient and scalable query building: https://danielbeck.io/posts/3-ways-to-manage-shopify-graphql-queries/
Might be helpful for this conversation.
You guys really need to build REAL apps, and not spread theory.
Here is an absolute WHOPPER of a bug in the Files api:
Try running this type of function:
public function getImageByName($filename, $used_in = '') {
# Define the fields to retrieve
$this->User->debug("getImageByName: $filename");
$fields = [
'nodes' => [
'... on MediaImage' => $this->mediaImageFieldsArray()
]
];
# Define query arguments (variable types)
$arguments = [
'query' => ['query' => 'String!'],
'first' => ['first' => 'Int!']
];
$queryConditions = ["(media_type:IMAGE)", "(status:READY)"];
$queryConditions[] = "(filename:$filename)";
if ($used_in) {
$queryConditions[] = "(used_in:'$used_in')";
}
# Define variables (actual values)
$variables = [
'query' => implode(" AND ", $queryConditions),
'first' => 200
];
$result = $this->getAllItems(
"getImageByName",
$this->queryGetItems('files', $fields, [$arguments]),
$variables
);
# Search for the image with the exact filename
foreach ($result as $item) {
if (!empty($item['image']['src']) && getFilename($item['image']['src']) === $filename) {
return $item;
}
}
return [];
}
Now run it on this store: “curalife-commerce.myshopify.com” and for the filename set it to “Group_1.png”
The code basically searches for “Group_1.png” in the files.
The way you have the API setup, is that filename:Group_1.png, returns ALL the files that are similar to Group_1.png
such as
Group_1597877377.png
Group_1597877346.png
Group_1597877347_2.png
…
This store literally has 1 MILLION files named Group something. I cant get it to stop, theres always a next page - its goes on for dozens of minutes fetching 250 results every second. TRY IT.
WHY DOESN’T THE API RETURN AN EXACT MATCH??? BROOOO
The WORKAROUND HACKS ARE RIDICULOUS. No more THEORY PLEASE.
Hi folks! I’m the PM for the files API. Thanks for the thorough feedback on these APIs, it really helps us continue to refine these to make them as consistent and ergonomic as possible. Agree, we have a lot of cleanup to do, and we’re actively working on it. On the media side, I can add a bit of context. First, we’re actively in the process of shipping updates to the search functionality to return exact match properly. You should see this landing very soon. On some of the other questions/points:
It is not clear on how to set the ‘Position’ of an image using GraphQl. It also does not return a Position key either so is the position only known from the order in the array?
We’re norming positions and ordering across all resources (specifically products, collections, and media). This unified position strategy will provide consistent explicit ordering inputs and will move us away from implicit ordering. No firm timeline, but we’re working on this.
It is not possible to retrieve the created_at and updated_at fields for product images when you fetch them with the product. Is the workaround to look up each image with the Files endpoint?
We’re working on adding created_at and updated_at as fields on the media object. This should be coming soon. For now, you can get these from the Media type Object.
On the rest, product images are a mix of ProductImage and MediaImage types. ProductImage type is not recognized in Graph. Looks like the older product images are coming up as ProductImage. Is this happening on Graph too, I have not been able to thoroughly investigate.
This is a result of our ongoing media simplification that deprecates resource-specific images in favour of unified media with a references system per shop. To assist in this, we wrote a migration guide and included mediaimage GIDs to REST to help get legacy GIDs if needed.
Rest api product images return variant_ids array field. This is very useful, otherwise we need to pull all variants and match up the image id with the image connected to the variant. Fortunately, the products/images.json endpoint isn’t on the chopping block… right?
This will become simpler once we deprecate images on variants, as you can already get variant media directly. In the near future there will also be a public references endpoint where you can use a media GID and get all its references (including variants, products, theme files, etc). Here’s a guide for the recommended way to use variant media today
Then, regarding the product specific questions here - here’s a few answers I was able to track down:
Getting presentment prices (for different currencies) using the GraphQl is very difficult to understand. Just one look at it made me turn back and use Rest.
In REST, presentment prices are a naive model that no longer represents the growing needs of our merchant base. Contextual pricing via the GraphQL api is much more powerful and better represents pricing on the platform - distinct markets and prices regardless of currency. We have a thorough guide on handling international pricing. Please let us know if you have feedback on the guide or any of these other points!
@jason_engage I want to thank you for the time an effort you put into presenting all the pain points about migrating to Graphql, you did it a heck of a lot more detailed than I could have.
There is just so much that is still not supported in graphql that is so easy to do in rest, and until the gaps are closed I will not be migrating any of our apps public or private and I do hope that Shopify will not force us to migrate to a system that can not provide us with the same features that REST does now just for the principle of it.
Regards
Thanks for putting together this post @jason_engage. I want to bring to attention something that is going to break our app when the deadline comes.
Rest has order.order_number
Graphql does not have this for some reason