### Install go-shopify Source: https://context7.com/bold-commerce/go-shopify/llms.txt Use go get to install the latest version of the library. ```bash go get github.com/bold-commerce/go-shopify/v4 ``` -------------------------------- ### Install go-shopify v3 Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Use 'go get' to install version 3 of the go-shopify library. ```console $ go get github.com/bold-commerce/go-shopify/v3 ``` -------------------------------- ### Install go-shopify v4 Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Use 'go get' to install version 4 of the go-shopify library. ```console $ go get github.com/bold-commerce/go-shopify/v4 ``` -------------------------------- ### Install go-shopify v2 Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Use 'go get' to install version 2 of the go-shopify library. ```console $ go get github.com/bold-commerce/go-shopify ``` -------------------------------- ### Import go-shopify v3 Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Import the goshopify package after installing v3. ```go import "github.com/bold-commerce/go-shopify/v3" ``` -------------------------------- ### Import go-shopify v4 Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Import the goshopify package after installing v4. ```go import "github.com/bold-commerce/go-shopify/v4" ``` -------------------------------- ### Import go-shopify v2 Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Import the goshopify package after installing v2. ```go import "github.com/bold-commerce/go-shopify" ``` -------------------------------- ### Fetch Product Count with Standard Options Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Use standard CountOptions to filter API results. This example fetches the number of products created after a specific date. ```go // Create standard CountOptions date := time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC) options := goshopify.CountOptions{createdAtMin: date} // Use the options when calling the API. numProducts, err := client.Product.Count(options) ``` -------------------------------- ### Shopify Client with API Version Option Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Example of creating a Shopify API client with a specific API version specified using the `WithVersion` option. This ensures compatibility with a particular Shopify API release. ```go client, err := goshopify.NewClient(app, "shopname", "", goshopify.WithVersion("2019-04")) ``` -------------------------------- ### Shopify API Calls with Access Token Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Example of making API calls to Shopify using a permanent access token obtained via OAuth. This demonstrates creating a client and fetching the product count. ```go // Create an app somewhere. app := goshopify.App{ ApiKey: "abcd", ApiSecret: "efgh", RedirectUrl: "https://example.com/shopify/callback", Scope: "read_products", } // Create a new API client client, err := goshopify.NewClient(app, "shopname", "token") // Fetch the number of products. numProducts, err := client.Product.Count(nil) ``` -------------------------------- ### Fetch Order Count with Custom Query Options Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Utilize custom structs with `url` tags to define query parameters for API requests. This example fetches order counts based on a 'status' field. ```go // Create custom options for the orders. // Notice the `url:"status"` tag options := struct { Status string `url:"status"` }{"any"} // Fetch the order count for orders with status="any" orderCount, err := client.Order.Count(options) ``` -------------------------------- ### Shopify OAuth Flow - Callback Handler Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Example of handling the callback from Shopify after OAuth authorization. This function verifies the callback signature and exchanges the authorization code for a permanent access token. ```go // Fetch a permanent access token in the callback func MyCallbackHandler(w http.ResponseWriter, r *http.Request) { // Check that the callback signature is valid if ok, _ := app.VerifyAuthorizationURL(r.URL); !ok { http.Error(w, "Invalid Signature", http.StatusUnauthorized) return } query := r.URL.Query() shopName := query.Get("shop") code := query.Get("code") ctx := context.TODO() // adds context which will be used in GetAccessToken below token, err := app.GetAccessToken(ctx, shopName, code) // Do something with the token, like store it in a DB. } ``` -------------------------------- ### Shopify Private App Authentication Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Example of authenticating with Shopify using a private app's API key and password. This method bypasses the OAuth flow and is suitable for server-to-server integrations. ```go // Create an app somewhere. app := goshopify.App{ ApiKey: "apikey", Password: "apipassword", } // Create a new API client (notice the token parameter is the empty string) client, err := goshopify.NewClient(app, "shopname", "") // Fetch the number of products. numProducts, err := client.Product.Count(nil) ``` -------------------------------- ### List and Manage Shopify Orders Source: https://context7.com/bold-commerce/go-shopify/llms.txt Fetch orders with various filters like status, financial status, and fulfillment status. Also demonstrates getting a single order, cancelling an order with a reason, and counting all orders. ```go ctx := context.Background() // Fetch all unfulfilled, paid orders updated after a date opts := goshopify.OrderListOptions{ Status: goshopify.OrderStatusOpen, FinancialStatus: goshopify.OrderFinancialStatusPaid, FulfillmentStatus: goshopify.OrderFulfillmentStatusUnfulfilled, ListOptions: goshopify.ListOptions{Limit: 250}, } orders, err := client.Order.ListAll(ctx, opts) if err != nil { log.Fatal(err) } for _, o := range orders { fmt.Printf("Order #%d total=%s items=%d\n", o.OrderNumber, o.TotalPrice, len(o.LineItems)) } // Get a single order order, _ := client.Order.Get(ctx, 123456789, nil) fmt.Println("Customer:", order.Customer.Email) // Cancel an order with a reason cancelOpts := goshopify.OrderCancelOptions{ Reason: string(goshopify.OrderCancelReasonCustomer), Email: true, } cancelled, _ := client.Order.Cancel(ctx, order.Id, cancelOpts) fmt.Println("Cancelled at:", cancelled.CancelledAt) // Count all orders regardless of status total, _ := client.Order.Count(ctx, struct { Status string `url:"status"` }{"any"}) fmt.Println("Total orders:", total) ``` -------------------------------- ### Shopify OAuth Flow - Authorize URL Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Example of creating an OAuth authorization URL for a Shopify app. This is typically done within an HTTP request handler to redirect the user to Shopify for authorization. ```go // Create an app somewhere. app := goshopify.App{ ApiKey: "abcd", ApiSecret: "efgh", RedirectUrl: "https://example.com/shopify/callback", Scope: "read_products,read_orders", } // Create an oauth-authorize url for the app and redirect to it. // In some request handler, you probably want something like this: func MyHandler(w http.ResponseWriter, r *http.Request) { shopName := r.URL.Query().Get("shop") state := "nonce" authUrl := app.AuthorizeUrl(shopName, state) http.Redirect(w, r, authUrl, http.StatusFound) } ``` -------------------------------- ### Build and Test with Make Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Use the provided Makefile for simplified development and testing. Commands include building the Docker image, running tests, cleaning up, and generating coverage reports. ```shell make && make test ``` -------------------------------- ### Configure go-shopify Client with Options Source: https://context7.com/bold-commerce/go-shopify/llms.txt Initialize the go-shopify client using `NewClient` and pass variadic `Option` functions to customize its behavior, such as API version, retry logic, logging, and HTTP client settings. ```go import ( "log" "net/http" "time" goshopify "github.com/bold-commerce/go-shopify/v4" ) app := goshopify.App{ApiKey: "key", ApiSecret: "secret"} client, err := goshopify.NewClient(app, "mystore", "shpat_token", // Pin to a specific Shopify API release goshopify.WithVersion("2024-01"), // Retry up to 5 times on 429 (rate limit) or 503 (service unavailable) goshopify.WithRetry(5), // Use a custom logger at Debug level goshopify.WithLogger(&goshopify.LeveledLogger{Level: goshopify.LevelDebug}), // Use an http.Client with a custom timeout and transport goshopify.WithHTTPClient(&http.Client{ Timeout: 45 * time.Second, Transport: &http.Transport{ MaxIdleConns: 10, IdleConnTimeout: 30 * time.Second, }, }), ) if err != nil { log.Fatal(err) } // After the first request, the negotiated API version is stored ctx := context.Background() _, _ = client.Shop.Get(ctx, nil) log.Printf("Negotiated API version: %s", client.RateLimits.RequestCount) // access rate limit info too ``` -------------------------------- ### Create and Manage Price Rules and Discount Codes Source: https://context7.com/bold-commerce/go-shopify/llms.txt Illustrates creating a percentage-off price rule with a minimum subtotal prerequisite and then creating a discount code associated with that rule. Ensure correct value types and date handling. ```go ctx := context.Background() // Create a 10% off discount rule for all products value := decimal.NewFromFloat(-10.0) rule, err := client.PriceRule.Create(ctx, goshopify.PriceRule{ Title: "10PERCENT", ValueType: "percentage", Value: &value, CustomerSelection: "all", TargetType: "line_item", TargetSelection: "all", AllocationMethod: "across", UsageLimit: 100, OncePerCustomer: true, StartsAt: func() *time.Time { t := time.Now(); return &t }(), }) if err != nil { log.Fatal(err) } fmt.Printf("PriceRule ID: %d\n", rule.Id) // Set prerequisite: cart subtotal >= $50 minSubtotal := "50.00" if err := rule.SetPrerequisiteSubtotalRange(&minSubtotal); err != nil { log.Fatal(err) } updated, _ := client.PriceRule.Update(ctx, *rule) fmt.Println("Updated rule:", updated.Id) // Create a discount code under this price rule code, _ := client.DiscountCode.Create(ctx, rule.Id, goshopify.DiscountCode{Code: "SAVE10"}) fmt.Println("Discount code:", code.Code) ``` -------------------------------- ### Create, List, and Update Shop Metafields Source: https://context7.com/bold-commerce/go-shopify/llms.txt Demonstrates how to create, list, and update shop-level metafields using JSON values. Ensure the correct MetafieldType is specified. ```go ctx := context.Background() // Create a shop-level metafield mf, err := client.Metafield.Create(ctx, goshopify.Metafield{ Namespace: "app_settings", Key: "feature_flags", Value: `{"beta_checkout": true}`, Type: goshopify.MetafieldTypeJSON, }) if err != nil { log.Fatal(err) } fmt.Printf("Created metafield: %s.%s = %v\n", mf.Namespace, mf.Key, mf.Value) // List all shop metafields mfs, _ := client.Metafield.List(ctx, nil) for _, m := range mfs { fmt.Printf(" %s.%s [%s]\n", m.Namespace, m.Key, m.Type) } // Update value mf.Value = `{"beta_checkout": false}` updated, _ := client.Metafield.Update(ctx, *mf) fmt.Println("Updated value:", updated.Value) ``` -------------------------------- ### Execute Shopify GraphQL Queries Source: https://context7.com/bold-commerce/go-shopify/llms.txt Demonstrates executing a GraphQL query to fetch product data and inspecting the GraphQL cost. Handles rate limiting errors by checking for `goshopify.RateLimitError`. ```go ctx := context.Background() type ProductNode struct { Id string `json:"id"` Title string `json:"title"` } type ProductEdge struct { Node ProductNode `json:"node"` } type ProductsConn struct { Edges []ProductEdge `json:"edges"` } type QueryResp struct { Products ProductsConn `json:"products"` } q := ` query getProducts($first: Int!) { products(first: $first) { edges { node { id title } } } } ` vars := map[string]interface{}{"first": 5} var resp QueryResp if err := client.GraphQL.Query(ctx, q, vars, &resp); err != nil { // RateLimitError is returned if retries are exhausted if rlErr, ok := err.(goshopify.RateLimitError); ok { fmt.Printf("Rate limited, retry after %d seconds\n", rlErr.RetryAfter) return } log.Fatal(err) } for _, edge := range resp.Products.Edges { fmt.Printf("Product: %s (%s)\n", edge.Node.Title, edge.Node.Id) } // Inspect GraphQL cost fmt.Printf("Query cost: %d / available: %.0f\n", client.RateLimits.GraphQLCost.RequestedQueryCost, client.RateLimits.GraphQLCost.ThrottleStatus.CurrentlyAvailable) ``` -------------------------------- ### API Calls with Token Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Demonstrates how to make API calls after obtaining an access token. ```APIDOC ## API Calls with Token ### Description With a permanent access token, you can make API calls like this. ### Usage 1. **Create an App Configuration**: Define your application's details. ```go app := goshopify.App{ ApiKey: "abcd", ApiSecret: "efgh", RedirectUrl: "https://example.com/shopify/callback", Scope: "read_products", } ``` 2. **Create a New API Client**: Instantiate the client using your app details, shop name, and the obtained token. ```go client, err := goshopify.NewClient(app, "shopname", "token") ``` 3. **Make API Calls**: Use the client to interact with Shopify resources, for example, fetching the product count. ```go // Fetch the number of products. numProducts, err := client.Product.Count(nil) ``` ``` -------------------------------- ### Import go-shopify Source: https://context7.com/bold-commerce/go-shopify/llms.txt Import the library with a custom alias for convenience. ```go import goshopify "github.com/bold-commerce/go-shopify/v4" ``` -------------------------------- ### Client Options - WithVersion Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Details how to specify a Shopify API version when creating the client. ```APIDOC ### Client Options - WithVersion #### Description When creating a client, there are configuration options you can pass to `NewClient`. The `WithVersion` option allows you to specify a particular version of the Shopify API. Read more details on the [Shopify API Versioning](https://shopify.dev/concepts/about-apis/versioning) to understand the format and release schedules. #### Usage ```go client, err := goshopify.NewClient(app, "shopname", "", goshopify.WithVersion("2019-04")) ``` ``` -------------------------------- ### client.Shop.Get Source: https://context7.com/bold-commerce/go-shopify/llms.txt Retrieves metadata about the authenticated store, including its name, domain, currency, timezone, and plan details. ```APIDOC ## client.Shop.Get — retrieve store information Fetch metadata about the authenticated store: name, domain, currency, timezone, plan, and more. ### Usage ```go ctx := context.Background() shop, err := client.Shop.Get(ctx, nil) if err != nil { log.Fatal(err) } fmt.Printf("Name: %s\nCurrency: %s\nTimezone: %s\nPlan: %s\n", shop.Name, shop.Currency, shop.IanaTimezone, shop.PlanName) // Output: // Name: My Shopify Store // Currency: USD // Timezone: America/New_York // Plan: basic ``` ``` -------------------------------- ### Client Options Source: https://context7.com/bold-commerce/go-shopify/llms.txt Configure the Shopify client using variadic Option functions such as WithVersion, WithRetry, WithLogger, and WithHTTPClient when creating a new client instance. ```APIDOC ## Client Options — WithVersion, WithRetry, WithLogger, WithHTTPClient All client options are passed as variadic `Option` functions to `NewClient`. ```go import ( "log" "net/http" "time" goshopify "github.com/bold-commerce/go-shopify/v4" ) app := goshopify.App{ApiKey: "key", ApiSecret: "secret"} client, err := goshopify.NewClient(app, "mystore", "shpat_token", // Pin to a specific Shopify API release goshopify.WithVersion("2024-01"), // Retry up to 5 times on 429 (rate limit) or 503 (service unavailable) goshopify.WithRetry(5), // Use a custom logger at Debug level goshopify.WithLogger(&goshopify.LeveledLogger{Level: goshopify.LevelDebug}), // Use an http.Client with a custom timeout and transport goshopify.WithHTTPClient(&http.Client{ Timeout: 45 * time.Second, Transport: &http.Transport{ MaxIdleConns: 10, IdleConnTimeout: 30 * time.Second, }, }), ) if err != nil { log.Fatal(err) } // After the first request, the negotiated API version is stored ctx := context.Background() _, _ = client.Shop.Get(ctx, nil) log.Printf("Negotiated API version: %s", client.RateLimits.RequestCount) // access rate limit info too ``` ``` -------------------------------- ### Fetch Webhooks Using Custom Models Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Implement custom models for data structures not yet supported by the library. Use `client.Get` to fetch resources and populate your custom models. ```go // Declare a model for the webhook type Webhook struct { Id int `json:"id"` Address string `json:"address"` } // Declare a model for the resource root. type WebhooksResource struct { Webhooks []Webhook `json:"webhooks"` } func FetchWebhooks() ([]Webhook, error) { path := "admin/webhooks.json" resource := new(WebhooksResource) client, _ := goshopify.NewClient(app, "shopname", "token") // resource gets modified when calling Get err := client.Get(path, resource, nil) return resource.Webhooks, err } ``` -------------------------------- ### Manage Inventory Levels Source: https://context7.com/bold-commerce/go-shopify/llms.txt Shows how to set absolute inventory levels, adjust stock counts by a relative delta, and list inventory levels for specific items across locations. Requires valid inventory and location IDs. ```go ctx := context.Background() inventoryItemId := uint64(11111) locationId := uint64(22222) // Set absolute inventory at a location level, err := client.InventoryLevel.Set(ctx, goshopify.InventoryLevel{ InventoryItemId: inventoryItemId, LocationId: locationId, Available: 100, }) if err != nil { log.Fatal(err) } fmt.Printf("Available at location %d: %d\n", level.LocationId, level.Available) // Adjust (relative delta) – add 10 units adjusted, _ := client.InventoryLevel.Adjust(ctx, goshopify.InventoryLevelAdjustOptions{ InventoryItemId: inventoryItemId, LocationId: locationId, Adjust: 10, }) fmt.Printf("New available: %d\n", adjusted.Available) // List inventory levels across locations for specific items levels, _ := client.InventoryLevel.List(ctx, goshopify.InventoryLevelListOptions{ InventoryItemIds: []uint64{inventoryItemId}, LocationIds: []uint64{locationId}, }) fmt.Printf("Found %d inventory levels\n", len(levels)) ``` -------------------------------- ### Generate Coverage Report with Docker Compose Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Create a coverage profile and generate an HTML report for Go tests using Docker Compose. ```shell docker-compose run --rm dev sh -c 'go test -coverprofile=coverage.out ./... && go tool cover -html coverage.out -o coverage.html' ``` -------------------------------- ### Build Test Image with Docker Compose Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Manually build the `go-shopify:latest` Docker image required for running tests using Docker Compose. ```shell docker-compose build test ``` -------------------------------- ### Create Authenticated API Client Source: https://context7.com/bold-commerce/go-shopify/llms.txt Construct a client for a specific store using OAuth or private app credentials. Functional options can configure API version, retries, logging, and the HTTP client. ```go package main import ( "context" "fmt" "log" "net/http" "time" goshopify "github.com/bold-commerce/go-shopify/v4" ) func main() { app := goshopify.App{ ApiKey: "your-api-key", ApiSecret: "your-api-secret", } // OAuth app client client, err := goshopify.NewClient( app, "mystore", // resolves to mystore.myshopify.com "shpat_accesstoken", goshopify.WithVersion("2024-01"), // pin API version goshopify.WithRetry(3), // retry on 429 / 503 goshopify.WithLogger(&goshopify.LeveledLogger{Level: goshopify.LevelInfo}), goshopify.WithHTTPClient(&http.Client{Timeout: 30 * time.Second}), ) if err != nil { log.Fatal(err) } // Private app (Basic Auth) – omit access token privateApp := goshopify.App{ApiKey: "apikey", Password: "apipassword"} privateClient, _ := goshopify.NewClient(privateApp, "mystore", "") shop, _ := client.Shop.Get(context.Background(), nil) fmt.Printf("Connected to: %s (%s)\n", shop.Name, shop.MyshopifyDomain) _ = privateClient } ``` -------------------------------- ### NewClient - Create an Authenticated API Client Source: https://context7.com/bold-commerce/go-shopify/llms.txt Constructs a *Client bound to a single store. Supports OAuth and private-app authentication. Functional options configure API version, retry behavior, logging, and the underlying http.Client. ```APIDOC ## NewClient — create an authenticated API client `NewClient` (or `MustNewClient`) constructs a `*Client` bound to a single store. Pass an `App` for credentials, the shop name, and a permanent access token. Functional options configure API version, retry behaviour, logging, and the underlying `http.Client`. ```go package main import ( "context" "fmt" "log" "net/http" "time" goshopify "github.com/bold-commerce/go-shopify/v4" ) func main() { app := goshopify.App{ ApiKey: "your-api-key", ApiSecret: "your-api-secret", } // OAuth app client client, err := goshopify.NewClient( app, "mystore", // resolves to mystore.myshopify.com "shpat_accesstoken", goshopify.WithVersion("2024-01"), // pin API version goshopify.WithRetry(3), // retry on 429 / 503 goshopify.WithLogger(&goshopify.LeveledLogger{Level: goshopify.LevelInfo}), goshopify.WithHTTPClient(&http.Client{Timeout: 30 * time.Second}), ) if err != nil { log.Fatal(err) } // Private app (Basic Auth) – omit access token privateApp := goshopify.App{ApiKey: "apikey", Password: "apipassword"} privateClient, _ := goshopify.NewClient(privateApp, "mystore", "") shop, _ := client.Shop.Get(context.Background(), nil) fmt.Printf("Connected to: %s (%s)\n", shop.Name, shop.MyshopifyDomain) _ = privateClient } ``` ``` -------------------------------- ### Initialize Client with Retry Option Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Configure the Shopify client to automatically retry requests that fail due to rate limiting or HTTP 503 errors. Specify the number of retry attempts. ```go client, err := goshopify.NewClient(app, "shopname", "", goshopify.WithRetry(3)) ``` -------------------------------- ### client.PriceRule Source: https://context7.com/bold-commerce/go-shopify/llms.txt Creates and manages Shopify discount rules, including percentage off, fixed amount, and free shipping, with support for prerequisite conditions. ```APIDOC ## client.PriceRule — create and manage discount rules `PriceRuleService` creates Shopify discount rules (percentage off, fixed amount, free shipping) that power discount codes. Supports prerequisite conditions on subtotal, quantity, and shipping price. ### Create a 10% off discount rule for all products ```go ctx := context.Background() value := decimal.NewFromFloat(-10.0) rule, err := client.PriceRule.Create(ctx, goshopify.PriceRule{ Title: "10PERCENT", ValueType: "percentage", Value: &value, CustomerSelection: "all", TargetType: "line_item", TargetSelection: "all", AllocationMethod: "across", UsageLimit: 100, OncePerCustomer: true, StartsAt: func() *time.Time { t := time.Now(); return &t }() }) if err != nil { log.Fatal(err) } fmt.Printf("PriceRule ID: %d\n", rule.Id) ``` ### Set prerequisite: cart subtotal >= $50 ```go ctx := context.Background() # Assuming rule is an existing PriceRule object minSubtotal := "50.00" if err := rule.SetPrerequisiteSubtotalRange(&minSubtotal); err != nil { log.Fatal(err) } updated, _ := client.PriceRule.Update(ctx, *rule) fmt.Println("Updated rule:", updated.Id) ``` ### Create a discount code under this price rule ```go ctx := context.Background() # Assuming rule is an existing PriceRule object code, _ := client.DiscountCode.Create(ctx, rule.Id, goshopify.DiscountCode{Code: "SAVE10"}) fmt.Println("Discount code:", code.Code) ``` ``` -------------------------------- ### Retrieve Authenticated Store Information Source: https://context7.com/bold-commerce/go-shopify/llms.txt Fetches metadata about the authenticated store, including its name, domain, currency, timezone, and plan. Requires a background context. ```go ctx := context.Background() shop, err := client.Shop.Get(ctx, nil) if err != nil { log.Fatal(err) } fmt.Printf("Name: %s\nCurrency: %s\nTimezone: %s\nPlan: %s\n", shop.Name, shop.Currency, shop.IanaTimezone, shop.PlanName) // Output: // Name: My Shopify Store // Currency: USD // Timezone: America/New_York // Plan: basic ``` -------------------------------- ### Shopify Product CRUD and Metafields Source: https://context7.com/bold-commerce/go-shopify/llms.txt Demonstrates full CRUD operations for products, including listing, counting, creating, updating, deleting, and managing metafields. Supports pagination for large product lists. ```go ctx := context.Background() // Count active products count, _ := client.Product.Count(ctx, goshopify.ProductListOptions{ Status: []goshopify.ProductStatus{goshopify.ProductStatusActive}, }) fmt.Println("Active products:", count) // Page through all products (cursor-based) opts := &goshopify.ProductListOptions{ ListOptions: goshopify.ListOptions{Limit: 50}, Status: []goshopify.ProductStatus{goshopify.ProductStatusActive}, } for { products, pagination, err := client.Product.ListWithPagination(ctx, opts) if err != nil { log.Fatal(err) } for _, p := range products { fmt.Printf(" [%d] %s (%s)\n", p.Id, p.Title, p.Status) } if pagination.NextPageOptions == nil { break } opts = pagination.NextPageOptions } // Create a product newProduct := goshopify.Product{ Title: "Premium Widget", BodyHTML: "Best widget ever.", Vendor: "Acme Corp", ProductType: "Widget", Status: goshopify.ProductStatusActive, Tags: "widget, premium", } created, err := client.Product.Create(ctx, newProduct) if err != nil { log.Fatal(err) } fmt.Printf("Created product ID: %d\n", created.Id) // Add a metafield to the product mf, _ := client.Product.CreateMetafield(ctx, created.Id, goshopify.Metafield{ Namespace: "custom", Key: "material", Value: "aluminum", Type: goshopify.MetafieldTypeSingleLineTextField, }) fmt.Printf("Metafield ID: %d\n", mf.Id) // Update title created.Title = "Premium Widget v2" updated, _ := client.Product.Update(ctx, *created) fmt.Println("Updated title:", updated.Title) // Delete _ = client.Product.Delete(ctx, created.Id) ``` -------------------------------- ### Private App Authentication Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Explains how to authenticate using private app credentials. ```APIDOC ## Private App Auth ### Description Private Shopify apps use basic authentication and do not require going through the OAuth flow. Here is an example: ### Usage 1. **Create an App Configuration**: Use your private app's API key and password. ```go app := goshopify.App{ ApiKey: "apikey", Password: "apipassword", } ``` 2. **Create a New API Client**: Instantiate the client. Note that the token parameter is an empty string for private apps. ```go // Create a new API client (notice the token parameter is the empty string) client, err := goshopify.NewClient(app, "shopname", "") ``` 3. **Make API Calls**: Use the client to interact with Shopify resources. ```go // Fetch the number of products. numProducts, err := client.Product.Count(nil) ``` ``` -------------------------------- ### Fetch and POST using Custom Models with client.Get/Post Source: https://context7.com/bold-commerce/go-shopify/llms.txt Use client.Get and client.Post with custom struct models for Shopify endpoints not directly supported by the library. Ensure your structs match the JSON structure of the Shopify API. ```go ctx := context.Background() // Fetch webhooks using custom models type MyWebhook struct { Id int `json:"id"` Topic string `json:"topic"` Address string `json:"address"` } type MyWebhooksResource struct { Webhooks []MyWebhook `json:"webhooks"` } resource := new(MyWebhooksResource) if err := client.Get(ctx, "webhooks.json", resource, nil); err != nil { log.Fatal(err) } for _, wh := range resource.Webhooks { fmt.Printf("[%d] %s → %s\n", wh.Id, wh.Topic, wh.Address) } // POST using custom data type ScriptTagPayload struct { ScriptTag struct { Event string `json:"event"` Src string `json:"src"` } `json:"script_tag"` } type ScriptTagResult struct { ScriptTag struct { Id int `json:"id"` Src string `json:"src"` } `json:"script_tag"` } payload := ScriptTagPayload{} payload.ScriptTag.Event = "onload" payload.ScriptTag.Src = "https://example.com/script.js" result := new(ScriptTagResult) _ = client.Post(ctx, "script_tags.json", payload, result) fmt.Println("Created script tag ID:", result.ScriptTag.Id) ``` -------------------------------- ### Create, Search, and Manage Shopify Customers Source: https://context7.com/bold-commerce/go-shopify/llms.txt Search for customers by email, create new customers with details and tags, list all orders for a specific customer, and retrieve all unique customer tags in the store. ```go ctx := context.Background() // Search customers by email results, _ := client.Customer.Search(ctx, goshopify.CustomerSearchOptions{ Query: "email:jane@example.com", Limit: 10, }) for _, c := range results { fmt.Printf("Customer: %s %s (%s)\n", c.FirstName, c.LastName, c.Email) } // Create a customer newCust := goshopify.Customer{ FirstName: "Jane", LastName: "Doe", Email: "jane@example.com", Tags: "vip, wholesale", } cust, err := client.Customer.Create(ctx, newCust) if err != nil { log.Fatal(err) } // Get all orders for a customer orders, _ := client.Customer.ListOrders(ctx, cust.Id, nil) fmt.Printf("Customer %d has %d orders\n", cust.Id, len(orders)) // Get all unique customer tags in the store tags, _ := client.Customer.ListTags(ctx, nil) fmt.Println("Tags:", tags) ``` -------------------------------- ### Custom Models with client.Get / client.Post Source: https://context7.com/bold-commerce/go-shopify/llms.txt Use the low-level client.Get, client.Post, client.Put, and client.Delete methods for Shopify endpoints not yet wrapped by a dedicated service, allowing you to use your own struct models for requests and responses. ```APIDOC ## Custom Models with client.Get / client.Post For any Shopify endpoint not yet wrapped by a dedicated service, use the low-level `client.Get`, `client.Post`, `client.Put`, and `client.Delete` methods with your own struct models. ```go ctx := context.Background() // Fetch webhooks using custom models type MyWebhook struct { Id int `json:"id"` Topic string `json:"topic"` Address string `json:"address"` } type MyWebhooksResource struct { Webhooks []MyWebhook `json:"webhooks"` } resource := new(MyWebhooksResource) if err := client.Get(ctx, "webhooks.json", resource, nil); err != nil { log.Fatal(err) } for _, wh := range resource.Webhooks { fmt.Printf("[%d] %s → %s\n", wh.Id, wh.Topic, wh.Address) } // POST using custom data type ScriptTagPayload struct { ScriptTag struct { Event string `json:"event"` Src string `json:"src"` } `json:"script_tag"` } type ScriptTagResult struct { ScriptTag struct { Id int `json:"id"` Src string `json:"src"` } `json:"script_tag"` } payload := ScriptTagPayload{} payload.ScriptTag.Event = "onload" payload.ScriptTag.Src = "https://example.com/script.js" result := new(ScriptTagResult) _ = client.Post(ctx, "script_tags.json", payload, result) fmt.Println("Created script tag ID:", result.ScriptTag.Id) ``` ``` -------------------------------- ### client.Product Source: https://context7.com/bold-commerce/go-shopify/llms.txt Provides comprehensive CRUD operations for products, including listing, retrieving, creating, updating, deleting, and managing metafields. ```APIDOC ## client.Product — full CRUD + pagination + metafields `ProductService` provides `List`, `ListAll`, `ListWithPagination`, `Count`, `Get`, `Create`, `Update`, `Delete`, and full metafield sub-resource methods. ### Usage ```go ctx := context.Background() // Count active products count, _ := client.Product.Count(ctx, goshopify.ProductListOptions{ Status: []goshopify.ProductStatus{goshopify.ProductStatusActive}, }) fmt.Println("Active products:", count) // Page through all products (cursor-based) opts := &goshopify.ProductListOptions{ ListOptions: goshopify.ListOptions{Limit: 50}, Status: []goshopify.ProductStatus{goshopify.ProductStatusActive}, } for { products, pagination, err := client.Product.ListWithPagination(ctx, opts) if err != nil { log.Fatal(err) } for _, p := range products { fmt.Printf(" [%d] %s (%s)\n", p.Id, p.Title, p.Status) } if pagination.NextPageOptions == nil { break } opts = pagination.NextPageOptions } // Create a product newProduct := goshopify.Product{ Title: "Premium Widget", BodyHTML: "Best widget ever.", Vendor: "Acme Corp", ProductType: "Widget", Status: goshopify.ProductStatusActive, Tags: "widget, premium", } created, err := client.Product.Create(ctx, newProduct) if err != nil { log.Fatal(err) } fmt.Printf("Created product ID: %d\n", created.Id) // Add a metafield to the product mf, _ := client.Product.CreateMetafield(ctx, created.Id, goshopify.Metafield{ Namespace: "custom", Key: "material", Value: "aluminum", Type: goshopify.MetafieldTypeSingleLineTextField, }) fmt.Printf("Metafield ID: %d\n", mf.Id) // Update title created.Title = "Premium Widget v2" updated, _ := client.Product.Update(ctx, *created) fmt.Println("Updated title:", updated.Title) // Delete _ = client.Product.Delete(ctx, created.Id) ``` ``` -------------------------------- ### Create, Complete, and List Shopify Fulfillments Source: https://context7.com/bold-commerce/go-shopify/llms.txt Create a new fulfillment for an order, including tracking information and notification settings. Also demonstrates completing a fulfillment and listing all fulfillments associated with an order. ```go ctx := context.Background() orderId := uint64(987654321) // Create a fulfillment with tracking info fulfillment := goshopify.Fulfillment{ TrackingInfo: goshopify.FulfillmentTrackingInfo{ Company: "FedEx", Number: "1234567890", Url: "https://www.fedex.com/tracking?id=1234567890", }, NotifyCustomer: true, LineItemsByFulfillmentOrder: []goshopify.LineItemByFulfillmentOrder{ {FulfillmentOrderId: 111222333}, }, } created, err := client.Fulfillment.Create(ctx, fulfillment) if err != nil { log.Fatal(err) } fmt.Printf("Fulfillment %d status: %s\n", created.Id, created.Status) // Complete a fulfillment completed, _ := client.Fulfillment.Complete(ctx, created.Id) fmt.Println("Completed:", completed.Status) // List fulfillments for an order via the order service list, _ := client.Order.ListFulfillments(ctx, orderId, nil) fmt.Printf("Order has %d fulfillments\n", len(list)) ``` -------------------------------- ### client.Webhook Source: https://context7.com/bold-commerce/go-shopify/llms.txt Enables subscription to Shopify events and verification of incoming webhook requests. ```APIDOC ## client.Webhook — subscribe and verify Manage webhook subscriptions and verify incoming requests from Shopify. ### Create Webhook Subscribes to a specific Shopify event topic. #### Parameters - `ctx` (context.Context) - The context for the request. - `webhook` (goshopify.Webhook) - The webhook subscription details, including topic, address, format, and fields. ### List Webhooks Retrieves a list of existing webhook subscriptions, optionally filtered by topic. #### Parameters - `ctx` (context.Context) - The context for the request. - `options` (goshopify.WebhookOptions) - Options for filtering the webhook list, such as by topic. ### Update Webhook Updates an existing webhook subscription. #### Parameters - `ctx` (context.Context) - The context for the request. - `webhook` (goshopify.Webhook) - The updated webhook object, including its ID. ### Delete Webhook Deletes a webhook subscription. #### Parameters - `ctx` (context.Context) - The context for the request. - `webhookID` (uint64) - The ID of the webhook to delete. ``` -------------------------------- ### Run Tests with Docker Compose Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Execute the test suite within the Docker environment using Docker Compose. ```shell docker-compose run --rm tests ``` -------------------------------- ### Remove Docker Image Source: https://github.com/bold-commerce/go-shopify/blob/master/README.md Clean up by removing the `go-shopify:latest` Docker image after testing. ```shell docker image rm go-shopify:latest ``` -------------------------------- ### client.Order Source: https://context7.com/bold-commerce/go-shopify/llms.txt Provides full CRUD operations for orders, including filtering, canceling, closing, and opening orders. The ListAll method automatically handles pagination to retrieve all matching orders. ```APIDOC ## client.Order — orders with filtering, cancel, close, open `OrderService` provides full CRUD plus `Cancel`, `Close`, and `Open` actions. `ListAll` automatically follows pagination to return every matching order. ### ListAll Orders Fetches all orders matching the specified options, automatically handling pagination. #### Parameters - `ctx` (context.Context) - The context for the request. - `opts` (goshopify.OrderListOptions) - Options for filtering and pagination. ### Get Order Retrieves a single order by its ID. #### Parameters - `ctx` (context.Context) - The context for the request. - `orderID` (uint64) - The ID of the order to retrieve. - `options` (*goshopify.OrderGetOptions) - Optional parameters for retrieving the order. ### Cancel Order Cancels an order with an optional reason and notification flag. #### Parameters - `ctx` (context.Context) - The context for the request. - `orderID` (uint64) - The ID of the order to cancel. - `options` (goshopify.OrderCancelOptions) - Options for cancellation, including reason and email notification. ### Count Orders Counts all orders in the store, regardless of their status. #### Parameters - `ctx` (context.Context) - The context for the request. - `options` (struct{ Status string `url:"status"` }) - Options for counting orders. Use `{"status": "any"}` to count all orders. ``` -------------------------------- ### client.GraphQL.Query Source: https://context7.com/bold-commerce/go-shopify/llms.txt Executes GraphQL queries against the Shopify API, automatically handling rate limiting and unmarshalling responses. ```APIDOC ## client.GraphQL.Query — execute GraphQL queries `GraphQLService.Query` POSTs to Shopify's `graphql.json` endpoint and unmarshals the `data` portion of the response into the supplied struct. It automatically handles GraphQL-level rate limiting with the configured `WithRetry` option. ### Execute a GraphQL query to get products ```go ctx := context.Background() type ProductNode struct { Id string `json:"id"` Title string `json:"title"` } type ProductEdge struct { Node ProductNode `json:"node"` } type ProductsConn struct { Edges []ProductEdge `json:"edges"` } type QueryResp struct { Products ProductsConn `json:"products"` } q := ` query getProducts($first: Int!) { products(first: $first) { edges { node { id title } } } } ` vars := map[string]interface{}{"first": 5} var resp QueryResp if err := client.GraphQL.Query(ctx, q, vars, &resp); err != nil { // RateLimitError is returned if retries are exhausted if rlErr, ok := err.(goshopify.RateLimitError); ok { fmt.Printf("Rate limited, retry after %d seconds\n", rlErr.RetryAfter) return } log.Fatal(err) } for _, edge := range resp.Products.Edges { fmt.Printf("Product: %s (%s)\n", edge.Node.Title, edge.Node.Id) } # Inspect GraphQL cost fmt.Printf("Query cost: %d / available: %.0f\n", client.RateLimits.GraphQLCost.RequestedQueryCost, client.RateLimits.GraphQLCost.ThrottleStatus.CurrentlyAvailable) ``` ``` -------------------------------- ### Shopify OAuth Flow Source: https://context7.com/bold-commerce/go-shopify/llms.txt Handles the OAuth process: redirecting merchants to Shopify, verifying the callback signature, and exchanging the authorization code for an access token. Ensure the App struct is configured with API key, secret, redirect URL, and scopes. ```go package main import ( "context" "fmt" "net/http" goshopify "github.com/bold-commerce/go-shopify/v4" ) var app = goshopify.App{ ApiKey: "abcd", ApiSecret: "efgh", RedirectUrl: "https://example.com/shopify/callback", Scope: "read_products,write_orders", } // Step 1: redirect merchant to Shopify func InstallHandler(w http.ResponseWriter, r *http.Request) { shopName := r.URL.Query().Get("shop") // e.g. "mystore.myshopify.com" state := "random-nonce-1234" authURL, err := app.AuthorizeUrl(shopName, state) if err != nil { http.Error(w, err.Error(), 500) return } http.Redirect(w, r, authURL, http.StatusFound) } // Step 2: handle callback, verify signature, exchange code for token func CallbackHandler(w http.ResponseWriter, r *http.Request) { if ok, err := app.VerifyAuthorizationURL(r.URL); !ok { http.Error(w, "invalid signature: "+err.Error(), http.StatusUnauthorized) return } shopName := r.URL.Query().Get("shop") code := r.URL.Query().Get("code") token, err := app.GetAccessToken(context.Background(), shopName, code) if err != nil { http.Error(w, err.Error(), 500) return } // persist token, then redirect fmt.Fprintf(w, "Token acquired: %s\n", token) } ```