Custom Shopify GraphQL Integration
A production-grade, ground-up GraphQL client built in C# on .NET 10 — no third-party SDKs, complete control over performance, error handling, and domain logic.
Overview
This library communicates directly with Shopify's Admin GraphQL API (version 2026-01), giving complete control over performance, error handling, and domain-specific business logic for print-on-demand fulfillment. It powers every aspect of Shopify integration — from OAuth authorization to product synchronization, fulfillment order processing, inventory management, webhook handling, and real-time storefront publishing.
Core Architecture
Strongly-Typed GraphQL Schema (47,000+ lines)
A comprehensive, auto-generated C# type system mirrors the full Shopify Admin GraphQL schema. Every Shopify object — products, variants, fulfillment orders, inventory items, locations, publications, metafields, and more — is represented as a strongly-typed C# class inheriting from GraphQLObject<T>.
- Compile-time safety — no magic strings or untyped dictionaries for Shopify data
- Full IntelliSense and refactoring support across the entire Shopify API surface
- Automatic JSON serialization/deserialization with
System.Text.Jsonand enum converters - Interface-driven connections —
IConnectionWithNodes<T>,IConnectionWithEdges<T>,IEdge<T>for Shopify's relay-style pagination model - Polymorphic media handling — typed interfaces (
IMedia,INode,INavigable,IHasMetafields,IHasEvents) for Shopify's union and interface types
GraphQL Service Layer
The ShopifyGraphQLService is the central HTTP transport layer responsible for:
- Building and sending GraphQL requests with typed
GraphRequestobjects (query + variables) - Deserializing responses into
GraphResult<T>with structured error, extension, and data payloads - Streaming JSON parsing via
JsonDocument.ParseAsyncfor memory-efficient response handling - Automatic credential resolution through an
IChannelCredentialProviderabstraction, decoupled from storage - Per-shop API URL construction using the Shopify store domain and configured API version
Rate Limiting & Throttle Management
Per-Shop Throttle Manager
A custom ShopifyThrottleManager implements Shopify's leaky-bucket cost model locally:
- Predictive waiting — before each request, estimates available capacity based on elapsed time and restore rate, sleeping only when the bucket would overflow
- Response-driven calibration — after each response, updates available points and restore rate from Shopify's actual
extensions.cost.throttleStatus - Thread-safe via
SemaphoreSlimfor concurrent request coordination
Throttle Registry
The ShopifyThrottleRegistry maintains a per-shop throttle manager using a concurrent dictionary keyed by store domain:
- Automatic lifecycle management — entries expire after 10 minutes of inactivity via a background cleanup timer
- Shared across all service instances — registered as a singleton for consistent rate limiting across the application
OAuth & Security
Full OAuth 2.0 Flow
- Authorization initiation — generates Shopify OAuth URLs with required scopes, CSRF state tokens, and callback URLs
- Token exchange — exchanges authorization codes for access tokens via Shopify's token endpoint
- Session management — persists auth sessions in the database with expiration tracking and refresh token support
- Reauthorization — supports seamless reauth when scopes change or tokens expire, with activity logging
Endpoint Security
- HMAC validation — every incoming Shopify webhook and callback is validated against the app's client secret using
ShopifySecurity.ValidateEndpointAsync - Domain validation — regex-based validation ensures shop domains match Shopify's
*.myshopify.compattern - Scope management — dynamic scope comparison detects missing permissions and triggers reauthorization flows
Auth Health Tracking
- Consecutive 401 tracking — the GraphQL service counts failed auth attempts per channel and sets a
NeedsReauthflag - Automatic recovery — successful API calls clear the auth failure state
- Unavailable shop detection — HTTP 402 responses with "Unavailable Shop" automatically mark channels as disconnected
Product Management
Product Creation & Synchronization
The ProductManager orchestrates the full product lifecycle between the local catalog and Shopify:
- Product creation via Shopify's
productSetmutation with synchronous mode for immediate confirmation - Full variant mapping — Color/Size option matrix with SKU-based matching between local and remote variants
- Image/media upload pipeline — uploads via
productCreateMedia, polls for readiness, attaches to variants viaproductVariantAppendMedia, with retry logic for Shopify's "non-ready media" race condition - Auto-publish to Online Store — discovers the Online Store publication ID and publishes products automatically
Product Updates
- Incremental variant sync — detects new, existing, and removed variants; links only missing ones
- Option value preservation — computes the union of existing and new option values to prevent data loss during
productSetupdates - Existing variant ID reuse — maps by SKU to update rather than recreate variants
Linked Product System
A local relational model (LinkedProduct → LinkedVariant) maintains the bidirectional mapping between internal merchant products and Shopify products:
- SKU-based primary matching with Color/Size fallback for variant linking
- Inventory item ID tracking per linked variant
- Cascade cleanup on product unlink — removes all linked variants and optionally the linked product record
Fulfillment Management
Fulfillment Service Lifecycle
- Automatic creation of the PrintAura fulfillment service in Shopify with callback URL configuration
- Fallback discovery — if creation fails (service already exists), queries existing services to find and record the PrintAura service
- ID repair utility —
FixFulfillmentServiceIdsAsyncreconciles missing or stale service/location IDs in local storage
Fulfillment Order Processing
- Assigned order retrieval — paginated cursor-based fetching of fulfillment orders assigned to PrintAura
- Fulfillment request acceptance — accepts submitted fulfillment requests via GraphQL mutation
- Fulfillment creation — creates fulfillments with tracking information (carrier, tracking number, tracking URL)
- Order conversion — address normalization, variant-to-line-item resolution via linked variant lookup, shipping calculation with pluggable
IShippingCalculator, tax exemption handling, and shipping discount application
Inventory Management
- Inventory activation — activates inventory items at the PrintAura fulfillment location
- Inventory deactivation — removes inventory from non-PrintAura locations
- Bulk toggle —
inventoryBulkToggleActivationfor batch location updates
Webhook System
Subscription Management
- Health check — queries current webhook subscriptions and compares against required topics
- Auto-registration — creates missing webhook subscriptions for required event topics
- Legacy cleanup — identifies and removes deprecated webhook topics from prior API versions
Required Event Topics
PRODUCTS_UPDATE | Syncs variant removals from Shopify back to linked products |
PRODUCTS_DELETE | Removes linked product records when products are deleted in Shopify |
APP_SCOPES_UPDATE | Detects permission changes |
APP_UNINSTALLED | Marks channels as disconnected on app removal |
FULFILLMENT_ORDERS_ORDER_ROUTING_COMPLETE | Tracks newly assigned orders for notification display |
FULFILLMENT_ORDERS_FULFILLMENT_REQUEST_SUBMITTED | Triggers order creation and fulfillment acceptance |
Webhook Processing
- Idempotency — webhook delivery IDs are tracked in a
WebhookDeliveriestable withINSERT IGNOREto prevent duplicate processing - Advisory locking — MySQL
GET_LOCKprevents concurrent webhook deliveries from creating duplicate orders - Fulfillment state reconciliation — every webhook triggers a state sync to update notification counts
Admin Dashboard Components (Blazor)
Connection Management
- Connect Shopify — OAuth flow initiation with environment-aware instructions (production vs. staging)
- Shopify Connection — full channel management: fulfillment service status, webhook subscriptions, permissions display, reauthorization, and channel deletion with confirmation modal
Monitoring Tools
- Store Monitor — displays all Shopify products with linked variant counts and fulfillment assignment status, color-coded for discrepancies
- Status Monitor — migration tracking dashboard showing products with temporary IDs, unlinked products, and migration issues
- Webhook Viewer — webhooks grouped by callback URL with formatted topic names and real-time health pulled from Shopify on page load
Technical Highlights
| Target Framework | .NET 10 / C# 14 |
| GraphQL Transport | Custom HttpClient-based with IHttpClientFactory |
| JSON Processing | System.Text.Json with streaming JsonDocument parsing |
| Database | Entity Framework Core with IDbContextFactory for scoped contexts |
| Concurrency | SemaphoreSlim throttling, MySQL advisory locks for webhook idempotency |
| Resilience | Retry strategies for DB operations, media upload retries, graceful degradation on API failures |
| Observability | Structured logging with ILogger<T>, activity log service for audit trails |
| Security | HMAC webhook validation, OAuth CSRF protection, credential isolation |
| UI Framework | Blazor Server with interactive components and real-time state management |
This library powers a production platform processing real merchant orders daily across many Shopify storefronts.