You can use a [Shopify Functions](/docs/apps/build/functions) to create network requests and handle responses. In this tutorial, you'll use [Cart and Checkout Validation Function API](/docs/api/functions/reference/cart-checkout-validation) to query an external system for user-specific cart limits based on the email they enter at checkout.
## What you'll learn
In this tutorial, you’ll learn how to do the following tasks:
- Define a function that declares an HTTP request to an external system, where additional information is available.
- Use the HTTP response to apply further logic to the function.
## Requirements
- You're using [Shopify CLI version 3.49.3 or higher](/docs/api/shopify-cli#upgrade).
- You have an HTTP server. In this tutorial, you'll use a NodeJS Express server.
## Step 1: Create the validation function
To create your validation function, you can use Shopify CLI to [generate](/docs/api/shopify-cli/app/app-generate-extension) a starter function, specify the inputs for your function using an [input query](/docs/apps/build/functions/input-output/metafields-for-input-queries), and implement your function logic using Javascript or Rust.
1. Navigate to your app directory:
1. Run the following command to create a new validation function:
> Tip:
> Shopify Functions support any language that compiles to WebAssembly (Wasm), such as Rust, AssemblyScript, or TinyGo. You specify the Wasm template option when you're using a language other than Rust and can conform to the Wasm API. [Learn more about the Wasm API](/docs/apps/build/functions/programming-languages/webassembly-for-functions).
1. Choose the language that you want to use. For this tutorial, you should select either **Rust** or **JavaScript**.
Shopify defaults to Rust as the most performant and recommended language choice to stay within the platform limits. For more information, refer to [language considerations](/docs/apps/build/functions/programming-languages).
1. Configure the extension definition in `shopify.extension.toml`. Add `[[targeting]]` sections to set up the following targets:
- `purchase.validation.fetch`: Declares a network HTTP request to an external system
- `purchase.validation.run`: Apply logic based off the network HTTP response
1. Define entry points for the `purchase.validation.fetch` and `purchase.validation.run` targets:
1. Update project dependencies and scripts. The `Cargo.toml` (Rust) and `package.json` (JavaScript) files contain metadata about your project. The files include project dependencies and scripts that let you run Shopify CLI commands using your package manager:
## Step 2: Retrieve the latest GraphQL schema
To use network access for Shopify Functions, you need to retrieve additional fields in the [Cart and Checkout Validation Function API](/docs/api/functions/reference/cart-checkout-validation) schema that relate to network access.
Run one of the following [Shopify CLI](/docs/apps/build/cli-for-apps) commands to retrieve the [latest GraphQL schema](/docs/apps/build/functions/input-output/network-access/graphql):
## Step 3: Create a network request using fetch
The `purchase.validation.fetch` target, exported as `fetch`, is used to declare a network request to an external system. You can use this target to fetch data required by your validation logic.
1. Create a file called `fetch.graphql` and define the input for the function. The input query can request any information available in the [Cart and Checkout Validation Function API](/docs/api/functions/reference/cart-checkout-validation):
The following example shows the resulting input from the query:
1. Navigate to your extension directory:
1. If you're using JavaScript, then run the following command to regenerate types based on your input query:
1. Create a file called `src/fetch.rs` (Rust) or `src/fetch.js` (JavaScript) and add the following code to the file:
The following example shows the output of the Function:
## Step 4: Handle the network request
The HTTP request is managed by Shopify, as set up by the `fetch` export. The HTTP response will be provided to the [next step](#step-5-create-the-validation-logic). The example in this section shows how to handle a network request from a Shopify Function, and includes information about the following areas:
- [Business logic](#business-logic)
- [JWT verification](#jwt-verification)
- [Server example](#server-example)
- [Exposing the server](#exposing-the-server)
### Business logic
The example server incorporates the following business logic:
- If the total cart amount exceeds 1,000, then the server must validate the following conditions:
- The buyer is authenticated. If not, then the server must return a validation error.
- The buyer provides an email that authorizes them to place an order. If not, then the server must return a validation error.
- If none of these conditions are met, then the server shouldn't return validation errors.
### JWT verification
Every request is accompanied by a verification header, `x-shopify-request-jwt`. This header contains a [JSON Web Token (JWT)](https://jwt.io/) that has been signed using the secret client key of the app. This token includes specific claims that assist in validating that the request was sent from Shopify.
### Server example
This guide offers a detailed, step-by-step process for creating a Remix app designed to handle network requests. Specifically, it focuses on handling POST requests that are accessible via the `/api` path.
1. First, you need to create a new Remix app. You can do this by running the following command in your terminal:
2. Next, navigate to your newly created Remix app directory and install the necessary dependencies. In this case, we will be installing `jsonwebtoken`:
3. Create the following files:
- `.env`: This file houses the environment variables for your application.
- **`routes/api.js`**: Outlines the action for the `/api` path to manage the incoming request. The code authenticates the request by verifying the JWT, and then executes the the associated business logic.
4. Execute the following command in your terminal to start the server:
### Exposing the server
The server used needs to be accessible on the public internet.
## Step 5: Create the validation logic
The `purchase.validation.run` target, exported as `run`, is used to apply logic based off the network response from an external system.
In the following example, the function takes the server response and returns it to Checkout as it is already formatted for validation errors. In a more complex use case, you could apply additional local logic in your function.
1. Create a file called `run.graphql` and define the input for the function. The GraphQL query takes the server response data as input.
The following example shows the resulting input to the query:
1. If you're using JavaScript, then run the following command to regenerate types based on your input query:
1. Create a file called `src/run.rs` (Rust) or `src/run.js` (JavaScript) and add the following code to the file:
The following example shows the output of the Function:
## Step 6: Preview the function on a development store
To test your function, you need to make it available to your development store.
1. If you're developing a function in a language other than JavaScript or TypeScript, ensure you have configured `build.watch` in your [function extension configuration](/docs/api/functions/configuration#properties).
1. Navigate back to your app root:
1. Use the Shopify CLI [`dev` command](/docs/api/shopify-cli/app/app-dev) to start app preview:
You can keep the preview running as you work on your function. When you make changes to a watched file, Shopify CLI rebuilds your function and updates the function extension's drafts, so you can immediately test your changes.
1. Follow the CLI prompts to preview your app, and install it on your development store.
## Step 7: Activate the validation
1. From the Shopify admin, go to **Settings** > **Checkout**.
1. In the **Checkout Rules** section of the page click **Add rule**.
A dialog opens and shows the `validation-using-network-access` function that you just deployed.
1. To add a validation, click **Add rule** and select the validation.
1. Click **Activate** to activate the validation.
1. Click on **Save**.
1. Optional: Control how checkout behaves when encountering runtime exceptions by clicking on the validation and selecting or deselecting **Allow all customers to submit checkout**.
## Step 8: Test the validation
1. From your online store, without logging in, create a cart with more then $1,000 in merchandise.
1. Proceed to **Checkout** and verify that a warning message displays.
1. Verify that checkout progress is blocked. Clicking the **Continue to shipping** button shouldn't redirect the user.
1. Using the Storefront API [`cartLinesAdd` mutation](/docs/api/storefront/2024-01/mutations/cartLinesAdd), confirm that the mutation's `userErrors` field contains the function's error message, and that executing the mutation was unsuccessful.
1. Open your terminal where `shopify app dev` is running, and review your function executions.
When [testing functions on development stores](/docs/apps/build/functions/test-debug-functions#test-your-function-on-a-development-store), the output of `dev` includes executions of your functions, any debug logging you have added to them, and a link to a local file with the full function execution details.
1. In a new terminal window, use the Shopify CLI [`app function replay`](/docs/api/shopify-cli/app/app-function-replay) command to [replay a function execution locally](/docs/apps/build/functions/test-debug-functions#execute-the-function-locally-using-shopify-cli), and debug your function without the need to re-trigger the function execution on Shopify.
1. Select the function execution from the top of the list. Press `q` to quit when you are finished debugging.
## Step 9: View the network access logs
To view network access logs, including request execution times and caching information, use [Shopify CLI log streaming](/docs/apps/build/functions/test-debug-functions#testing-on-your-development-store).
## Next step
- Consult the [GraphQL reference for Functions](/docs/apps/build/functions/input-output/network-access/graphql).