ShopifySharp 6.26.0 Release Notes
ShopifySharp version 6.26.0 has been released, and with it comes support for version 2026-01 of Shopify’s Graph and Rest APIs, along with regenerated GraphQL types to match the new API version, and brand-spanking new fluent query builders for all GraphQL queries and mutations. If that piques your interest, keep reading!
Fluent GraphQL query builders
Section titled “Fluent GraphQL query builders”I worked my hands to the bone to bring you one of the slickest features ShopifySharp’s ever seen: fluent-style GraphQL query builders! And no, it’s not just a wrapper around somebody else’s GraphQL library! These query builders are custom built for ShopifySharp specifically, slotting right into the GraphService, with the goal of making it as easy as possible for you to use Shopify’s GraphQL API without needing to write raw queries by hand.
Just like the pre-generated GraphQL types that were already included in previous ShopifySharp releases, these new fluent query builders are automatically generated by parsing Shopify’s GraphQL schema file. There’s a query builder for every graph query and mutation defined in Shopify’s 2026-01 schema, and every type that’s reachable by those queries and mutations. If you notice one is missing, please let me know!
Let’s look at a simple example, querying the user’s shop:
using ShopifySharp;using ShopifySharp.GraphQL.Generated.QueryBuilders.Operations;
var builder = new ShopOperationQueryBuilder() .Id() .Name() .MyshopifyDomain() .OrderNumberFormatPrefix() .OrderNumberFormatSuffix() .Plan(plan => { plan.PartnerDevelopment() .PublicDisplayName() .Plus(); });At this point, you could call builder.Build() to serialize the builder to a graphql query string. But these query builders are meant to work directly with ShopifySharp’s GraphService class, which means you can just pass it directly to the new PostAsync<T>(GraphRequest<T>, CancellationToken) method. The method will A) serialize that query for you; and B) infer the return type and deserialize it without needing a wrapper class or even needing to specify the return type yourself:
using ShopifySharp;using ShopifySharp.GraphQL.Generated.QueryBuilders.Operations;
var builder = new ShopOperationQueryBuilder() .Id() .Name() .MyshopifyDomain() .OrderNumberFormatPrefix() .OrderNumberFormatSuffix() .Plan(plan => { plan.PartnerDevelopment() .PublicDisplayName() .Plus(); });
var result = await graphService.PostAsync(GraphRequest.FromQueryBuilder(builder));// GraphService.PostAsync knows the return type of this request thanks to the interfaces on the query builder,// meaning result.Data is a ShopifySharp.GraphQL.Generated.Shopvar shop = result.Data;
Console.WriteLine("Shop name is {0}", shop.name); // "Shop name is Foo Shop"The query builders support mutations and arguments as well:
var productId = "gid://shopify/Product/123";var builder = new ProductCreateOperationQueryBuilder() .Product(product => { product.Id() .Title() .Variants(variant => { variant.Id() .Sku() .Title() .Price(); }); } .UserErrors(userErrors => { userErrors.Field() .Message(); });// Add the mutation's input argumentsbuilder.Arguments.Product(new ProductCreateInput{ title = "Foo Product", handle = "foo-product", productOptions = [ // Your product options here ]});
var request = GraphRequest.FromQueryBuilder(builder);// By default, the GraphRequest is configured to throw if there are any "UserErrors" returned by the mutation response.// Configure this behavior using the GraphRequest.UserErrorHandling property.// request.UserErrorHandling = GraphRequestUserErrorHandling.DoNotThrow;
var result = await graphService.PostAsync(request);// The type of result.Data is ShopifySharp.GraphQL.ProductCreatePayloadvar payload = result.Data;
Console.WriteLine("Product title is {0}", payload.product.title); // "Product title is Foo Product"Union cases are a big part of the GraphQL spec, too, so the query builders support them by default.
GraphRequest<T> requires an IGraphOperationQueryBuilder<T>
Section titled “GraphRequest<T> requires an IGraphOperationQueryBuilder<T>”The GraphRequest<T> class that supports the interop between the GraphService and the new query builders specifically requires an IGraphOperationQueryBuilder<T>. However, not all query builders implement that interface. This is intentional, as ShopifySharp includes pre-generated query builders for regular graph types, and query builders for operations (aka queries and mutations). In GraphQL, you can send a request for a query or an operation at the top level, but it doesn’t make sense to send one for a plain type. The interface here is meant to help restrict the types of query builders passed to the method to only those that represent top-level operations.
Credit to Mr. de Vandière
Section titled “Credit to Mr. de Vandière”Shout out and credit to Charles de Vandière and his project GraphQL Query Builder .NET, which is where the inspiration for ShopifySharp’s fluent query builders was drawn. Proper credit and attribution to Mr. de Vandière has been added to ShopifySharp’s attributions file, and as MIT attribution headers in the code files (listed in the attributions file).
What else changed in this release?
Section titled “What else changed in this release?”ShopifySharp 6.26.0 now targets version 2026-01 of Shopify’s GraphQL and Rest APIs, so make sure you update your GraphQL schema file to match if you’re using a GraphQL plugin in your IDE. You can download the updated 2026-01 schema file from the ShopifySharp repository in both json and graphql formats right here.
Accordingly, all pre-generated GraphQL types have been updated and regenerated for 2026-01. If you were using a pre-generated type that changed or was removed entirely between the previous version we supported and the new version, please direct your blame at Shopify.
Rounding out these version updates, ShopifySharp’s framework targets have been upgraded from .NET 8 and .NET Standard 2.0 to .NET 10 and .NET Standard 2.0.
GraphService automatically unwraps single object GraphQL queries
Section titled “GraphService automatically unwraps single object GraphQL queries”The GraphService.PostAsync<T>(GraphRequest, CancellationToken?) method no longer requires a wrapper/container class for deserializing the result when your query contains a single top-level object. Instead, the service will attempt to unwrap the result into the type parameter T, letting you drop those wrapper/container classes. This was a common “gotcha” with the GraphService in ShopifySharp.
Before ShopifySharp 6.26.0:
public record GraphQueryResult<T>(){ public T Result { get; set; }}
var graphRequest = new GraphRequest{ // Set an alias on the shop object to make it work with the generic wrapper class Query = " result: shop { id legacyResourceId orderNumberFormatPrefix orderNumberFormatSuffix name } "};var result = await graphService.PostAsync<GraphQueryResult<ShopifySharp.GraphQL.Shop>>(graphRequest);// Get the shop from the wrapper classvar shop = graphRequest.Data.Result;
Console.WriteLine("Shop name is {0}", shop.name); // "Shop name is Foo Shop"In ShopifySharp 6.26.0 and beyond, we can drop that wrapper class entirely when querying a single object or mutation:
var graphRequest = new GraphRequest{ // Note: no alias is set an alias here Query = " shop { id legacyResourceId orderNumberFormatPrefix orderNumberFormatSuffix name } "};var result = await graphService.PostAsync<ShopifySharp.GraphQL.Shop>(graphRequest);// The GraphService automatically deserializes the .Data property to type ShopifySharp.GraphQL.Shopvar shop = graphRequest.Data;
Console.WriteLine("Shop name is {0}", shop.name); // "Shop name is Foo Shop"This change is backwards compatible; if you’re using wrapper classes right now (you probably are if you’re using this method), you don’t need to change anything when upgrading ShopifySharp to 6.26.0.
Deprecations
Section titled “Deprecations”The long-deprecated static AuthorizationService class has been removed. It was deprecated almost two years ago. To replace its functionality, you should use the ShopifyOauthUtility, ShopifyRequestValidationUtility and ShopifyDomainUtility classes instead, which all have proper interfaces for test mocking and dependency injection (via the ShopifySharp.Extensions.DependencyInjection package).
Additionally, several deprecated, protected GraphService methods were removed. This should only affect you if you were extending the GraphService class and were using one of those methods. In general, those deprecated methods were all replaced with the protected SendAsync method.
Bug fixes
Section titled “Bug fixes”- Possibly breaking change: the generated GraphQL types now use
DateTimeOffsetinstead ofDateTime. Depending on how you were using these date values, it’s possible they were dropping timezone information during serialization/deserialization depending on your machine’s location (Shopify uses UTC by default). - Possibly breaking change: the type of
ShopifySharp.Address.Namehas changed fromstringtostring?to fix an issue where the presence of any value in aCustomer.Address.Name(it’s auto-populated by Shopify) during an update to the entity via the Rest API would cause Shopify to return an error.
Plans for supporting the Rest API and ShopifySharp 7.0 release
Section titled “Plans for supporting the Rest API and ShopifySharp 7.0 release”I plan on supporting Shopify’s Rest API for as long as Shopify themselves support it. They continue to maintain the Rest API and release new versions for it alongside the Graph API, despite it being deprecated, though no new apps can be published using the Rest API.
My plan for ShopifySharp 7.0 is to:
- A) move any service supporting the Rest API into a legacy
ShopifySharp.Services.Legacy.Restnamespace - B) move all Rest API entity types into a similar namespace
- C) remove the current compiler warnings that I’ve set on many of those Rest API services
I will also be converting the generated GraphQL property names to CamelCase in ShopifySharp 7.0.
Support ShopifySharp
Section titled “Support ShopifySharp”A sincere thank you to everyone who has supported ShopifySharp by reporting bugs, requesting new features, suggesting changes and contributing code. A big thanks as well to those who’ve supported ShopifySharp monetarily through Github.
If you find ShopifySharp useful, please consider contributing to the project! You can do so by sponsoring me here on Github, or by purchasing a copy of The Shopify Development Handbook on Gumroad.