Skip to main content

Build a Discount Function that has network access

In this tutorial, you'll build a Shopify Function that validates discount codes against an external system then applies valid discounts to a buyer's cart. Using network access, you'll configure HTTP requests to fetch data from external services and provide that data as input to your run Function. To learn more, see network access for Shopify Functions.

Shopify for enterprise

Network access for Shopify Functions is limited to Shopify for enterprise plans. For more information, contact our enterprise sales team.

In this tutorial, you'll learn how to do the following tasks:

  • Add a network request to your Function.
  • Respond to the network request with a mock HTTP server.
  • Create a tunnel using a service like Ngrok to expose your mock HTTP server to the internet.
  • Deploy your Function to Shopify.
  • Review logs for your Function.
  • Test your Function in checkout.

Requirements

Scaffold an app with a Discount Function

For example, follow the Build a Discount Function tutorial, or build your own app and Discount Function using the Discount API.

Project

Using the app you already have, or the one you created by completing the Build a Discount Function tutorial, you can add network access to your Function.

Anchor to Update your Function to access the networkUpdate your Function to access the network

In this step, you'll update your Function to access the network and use the fetchResult in the run target's input query.

Anchor to Add network access targetsAdd network access targets

To access a network from your Shopify Function, add the cart.lines.discounts.generate.fetch and cart.delivery-options.discounts.generate.fetch targets to your shopify.extension.toml file.

The [[extensions.targeting]] sections define the Function targets. Each section includes a target, input_query, and export property.

The target property defines where the Function is applied. There are two network access targets:

  • cart.lines.discounts.generate.fetch: This target runs before the cart.lines.discounts.generate.run target.
  • cart.delivery-options.discounts.generate.fetch: This target runs before the cart.delivery-options.discounts.generate.run target.

The input_query property is the path to the Function's input query file. The input query file defines the Function's input parameters.

The export property specifies the entry point for your Function's discount calculation logic.

Anchor to Query the ,[object Object], for the cart fetch targetQuery the enteredDiscountCodes for the cart fetch target

Create a cart_lines_discounts_generate_fetch.graphql input query file that provides data to your Function. This allows you to conditionally build an HTTP request that is then executed by Shopify. For example, you can query enteredDiscountCodes, which allow you to perform validations against your external service.

Anchor to Query the ,[object Object], for the delivery fetch targetQuery the enteredDiscountCodes for the delivery fetch target

Create a cart_delivery_options_discounts_generate_fetch.graphql input query file that provides data to your Function. This allows you to conditionally build an HTTP request that is then executed by Shopify. For example, you can query enteredDiscountCodes, which allow you to perform validations against your external service.

Anchor to Query the ,[object Object], for the cart run targetQuery the fetchResult for the cart run target

Update the cart_lines_discounts_generate_run.graphql file. The fetchResult from the fetch request will be the input to your cart.lines.discounts.generate.run target. Refer to Discount API for more information about the input data available to your Function.

Anchor to Query the ,[object Object], for the delivery run targetQuery the fetchResult for the delivery run target

Update the cart_delivery_options_discounts_generate_run.graphql file. The fetchResult from the fetch request will be the input to your cart.delivery-options.discounts.generate.run Function. Refer to Discount API for more information about the input data available to your Function.

Anchor to Add an export for the cart fetch targetAdd an export for the cart fetch target

Shopify uses the cart.lines.discounts.generate.fetch target to build an HTTP request, which it executes and provides to your run target as input.

Anchor to Add an export for the delivery fetch targetAdd an export for the delivery fetch target

Shopify uses the cart.delivery-options.discounts.generate.fetch target to build an HTTP request, which it executes and provides to your run target as input.

Anchor to Parse the result from the network call in the cart run targetParse the result from the network call in the cart run target

Update the cart.lines.discounts.generate.run target to handle the response from the network call. This target parses the fetchResult from the network call and uses it to apply a discount to the cart lines.

Anchor to Parse the result from the network call in the delivery run targetParse the result from the network call in the delivery run target

Update the cart.delivery-options.discounts.generate.run target to handle the response from the network call. This target parses the fetchResult from the network call and uses it to apply a discount to the delivery options.

Anchor to Export the fetch request targets in your main fileExport the fetch request targets in your main file

Add the cart_lines_discounts_generate_fetch and cart_delivery_options_discounts_generate_fetch exports to the main.rs file. The main.rs file is the entry point for your Shopify Function.

Anchor to Ensure the name of the function package, matches the handle of your FunctionEnsure the name of the function package, matches the handle of your Function

In the Cargo.toml file, ensure the name of the function package matches the handle of your Function. The handle is the name you provided when you created your Function and it can be found in the shopify.extension.toml file.

Anchor to Re-generate the schemaRe-generate the schema

You must regenerate the new Discount API schema to support the new properties you added to your Function Input and Output.

Terminal

shopify app function schema

Anchor to Set up a web service to respond to your Function's network requestsSet up a web service to respond to your Function's network requests

To provide network access to your Function, set up an external service that can respond to the HTTP requests that Shopify will make on behalf of your Function.

When your Shopify Function runs, it cannot make network requests directly. Instead, Shopify makes the requests on behalf of your Function to URLs you specify. In a production environment, this would typically be an API endpoint within your existing infrastructure. For this tutorial, we'll create a simple mock HTTP server.

Caution

When you test this server in development, there is no URL validation against the value found in the JSON web token. Since the URL of your tunnel can change often, you can ignore validating the URL. In production, you should validate the URL to ensure it matches the value found in the JSON web token.

Anchor to Setup a mock HTTP server with RemixSetup a mock HTTP server with Remix

Info

This is a separate app from your Shopify App. Create it in a new folder outside your Shopify app.

  1. Create a new Remix app from the Remix template:

In a separate folder from your Shopify app, run the following command to create a new Remix app. This will create a new directory called mock-http-server with the Remix app inside it.

Terminal

npx create-remix@latest mock-http-server --template remix-run/remix/templates/remix-javascript
  1. Navigate to the mock HTTP server directory

Terminal

cd mock-http-server
  1. Install the jsonwebtoken package:

Terminal

npm i jsonwebtoken

Anchor to Create an API route in the routes directoryCreate an API route in the routes directory

Create a file named api.js in the /routes directory of the mock-http-server app. The code authenticates the request by verifying the JWT, and then executes the the associated business logic, which returns discount operations.

Anchor to Review the response from the mock HTTP serverReview the response from the mock HTTP server

The mock HTTP server responds to your Function's HTTP requests, which are made by Shopify with an object similar to this sample code. This object can then be queried as the fetchResult for the input of your cart.lines.discounts.generate.run and cart.delivery-options.discounts.generate.run targets.

Anchor to Create an environment file in the root of your appCreate an environment file in the root of your app

This file contains the environment variables for your application:

  • APP_CLIENT_SECRET: Find this on your App's overview page in the Partner Dashboard
  • JWT_SHOP_ID: Find this in the URL of your Store's overview page in the Partner Dashboard

Anchor to Run your mock HTTP server locallyRun your mock HTTP server locally

Run your mock HTTP server locally using the following command:

Terminal

npm run dev

Anchor to Use a service like Ngrok to expose your local server to the internet.Use a service like Ngrok to expose your local server to the internet.

To setup Ngrok, follow these steps. Then you can create a tunnel to your local server.

In a separate terminal, start the Ngrok tunnel:

Terminal

ngrok http 5173

In your cart_lines_discounts_generate_fetch.rs file, replace the url with that of the Ngrok tunnel you created in the previous step.

Terminal

https://<ngrok-url>/api

In your cart_delivery_options_discounts_generate_fetch.rs file, replace the url with that of the Ngrok tunnel you created in the previous step.

Terminal

https://<ngrok-url>/api

Anchor to Add your tunnel URL to the list of allowed hosts in your mock-http-server's Vite configAdd your tunnel URL to the list of allowed hosts in your mock-http-server's Vite config

To allow your tunnel to proxy traffic to localhost, add the tunnel URL to the list of approved hosts in your Vite config. This is necessary because Vite uses a proxy to forward requests to your local server. Don't include the https:// or http:// prefix in the URL.

Anchor to Deploy your updated functionDeploy your updated function

  1. Deploy your updated configuration to Shopify:

    Terminal

    shopify app deploy
  2. Restart your app development server:

    Terminal

    shopify app dev
  3. Open or reinstall your app using the URL provided by Shopify CLI. To preview your extensions, press p in the terminal window where you started your app.

  4. Accept the new access scope permissions in your store.

Anchor to Test the discount with network accessTest the discount with network access

Anchor to Trigger the discount on your development storeTrigger the discount on your development store

  1. From your Shopify admin, go to Discounts. You should now see the Cart line, order and shipping that you created.
    An image showing a list of all active discounts for the store.
  2. Open your development store and build a cart with a single item in it.
  3. Add 10OFFPRODUCT, 20OFFORDER, and FREESHIPPING codes in the Discount codes or gift card field.
  4. After you navigate to the checkout page, shipping discounts display on the checkout page after you provide your shipping address.

Anchor to Review the Function executionReview the Function execution

  1. In the terminal where shopify app dev is running, review your Function executions.

    When testing Functions on development stores, the dev output shows Function executions, debug logs you've added, and a link to a local file containing full execution details.

  2. In a new terminal window, use the Shopify CLI command app function replay to replay a Function execution locally. This lets you debug your Function without triggering it again on Shopify.

    Terminal

    shopify app function replay
  3. Select the Function execution from the top of the list. Press q to quit when you are finished debugging.

Was this page helpful?