Shopify Webhooks with Begin
Tags: aws, shopify, webhooks, javascript
Published: 2021-11-30 17:13:53

<small>Photo by [Tatiana Rodriguez](https://unsplash.com/photos/TxzjVxnWYq4)</small>

It’s always nice when data comes to you, and even better if your program can react in real-time. [Shopify offers helpful webhooks](https://shopify.dev/apps/webhooks) for all sorts of store events. A developer just needs to set up a way to listen for those hooks and act on their data.

Shopify does offer [support for AWS EventBridge](https://shopify.dev/apps/webhooks/eventbridge) and [GCP Pub/Sub](https://shopify.dev/apps/webhooks/google-cloud). Unfortunately, the process for both requires some web console spelunking, subscribing to webhook topics programmatically via the Shopify API (eventually, a good idea), and then setting up a mechanism to actually do work on the data.

Instead, let’s leverage the power and scale of AWS with the ease of [Architect](https://arc.codes) and [Begin](https://begin.com). Without managing AWS projects, IAM roles, or connecting EventBridge to a series of Lambdas.

Architect will help set up various HTTP routes (API Gateway endpoints backed by Lambda functions) to handle incoming webhook data. As an example, we’ll listen for customer updates and check if they're a VIP (10 or more lifetime orders).

## Create a new Architect app with `npm init`

```sh
npm init @architect shopify-webhooks
cd shopify-webhooks
```

Architect has created the foundation for a new Arc project with a single HTTP endpoint. You can get a good view of what an Arc project is about by viewing [the `./app.arc` file](https://arc.codes/docs/en/get-started/project-manifest).

## Add an HTTP function called "customer-update"

Create a new entry in the app’s manifest. We'll use the "post" prefix to declare an endpoint that will respond to POST requests like webhooks from Shopify.

```
@app
shopify-webhooks

@http
get /
post /customer-update
```

Architect's CLI can help by creating some scaffolding. Just run `arc create`:

```sh
npx arc create
# ✓ Create Existing Architect project manifest found
# ✓ Create Created new project files in src/http/post-customer_update/
# ✓ Create Done!
```

## Update the `customer-update` handler function

First, let's add the [`@architect/functions`](https://arc.codes/docs/en/reference/runtime-helpers/no#%40architect%2Ffunctions) helper.  
This library has some utilities to help parse request bodies, handle asynchronous code, and more. It's also available in Ruby and Python. Yep, this entire workflow can be done with [alternative runtimes](https://arc.codes/docs/en/reference/configuration/function-config#runtime).

```
npm i @architect/functions
```

We'll add some very simple code to `src/http/post-customer_update/index.js` that will acknowledge a webhook request and decide what to log based on a customer's total order count.

```js
const arc = require("@architect/functions");
function handler(request, response) {
  response({ status: 200 }); // respond immediately
  const customer = request.body;
  console.log(`${customer.id} was updated`);
  if (customer.orders_count > 9) {
    console.log(`${customer.id} is a VIP 🎉`);
  } else {
    console.log(`${customer.id} has ${customer.orders_count} orders`);
  }
}
exports.handler = arc.http(handler);
```

## Test locally with [Architect Sandbox](https://arc.codes/docs/en/reference/cli/sandbox)

Architect has a Sandbox to help test our functions locally. Fire it up:

```sh
npx arc sandbox
```

Navigate to http://localhost:3333 to confirm the server is running and see `get-index` in action.

Next, we can test our new endpoint locally with a curl POST:

```sh
curl -X POST http://localhost:3333/customer-update \
   -H 'Content-Type: application/json' \
   -d '{"id": 706405506930370084,"email": "bob@biller.com","orders_count": 0}'
```

Checking the Sandbox logs, we can see the customer’s id was logged to the console.

```sh
706405506930370084 was updated
706405506930370084 has 0 orders
```

Try sending the curl command again but set “orders_count” to 10. This time the customer is logged as a VIP 🎉

```sh
706405506930370084 was updated
706405506930370084 is a VIP 🎉
```

## Deploy to Begin.com

Let's get this to the cloud! Architect lets developers deploy directly to an existing AWS account if a local profile is set up.

Instead, we'll make it even easier and deploy it to [Begin.com](https://begin.com). First, push the Arc project to a new GitHub repository. Then head to Begin.com (and make an account if needed) to create a new app.

Select "Use an existing repo" and choose the GitHub repository we just created.

![select a repo at Begin.com](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8tgvaq0j74km9quh6ir8.png) 

A staging build will kick off immediately. After that succeeds, go ahead and deploy to production. Once that's complete, you can click the production link to open the project's live version.

## Configure Shopify with Begin’s new URL

Head over to the admin for the Shopify store you're working with. In store settings, under Notifications, add a new webhook. Set the topic to "Customer update" and use the production URL from Begin with the added `/customer-update` path.

![create a Shopify webhook](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nwiy0pp05r825l1jtv44.png) 

## Send a sample event from Shopify

After saving the webhook in Shopify, click "Send test notification" next to the new event. This will POST a test payload to the live project deployed on Begin.

From the Begin app dashboard, open the `customer-update` function logs from the HTTP view to check the production logs.

![Begin application logs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5mi84onbvm9ioqofnsl4.png) 

Just like that, we're catching Shopify webhooks in production with AWS Lambdas, no complex set up required.

## Next steps

Okay, now what? Well, that's up to you and your app's needs. Here are some suggestions from my time in the Shopify ecosystem:

1. Verify [the webhook signature](https://shopify.dev/apps/webhooks/https#verify-a-webhook).
1. Save data to a database; like [Begin's built-in tables](https://docs.begin.com/en/data/begin-data/).
1. POST data back to Shopify's API, like adding a `VIP` [customer](https://shopify.dev/api/admin-rest/2021-10/resources/customer) tag.
1. Publish to an event queue (SNS) with [the @events pragma](https://arc.codes/docs/en/reference/project-manifest/events).
1. Handle Shopify's [mandatory webhooks](https://shopify.dev/apps/webhooks/mandatory).
1. Reduce repetition by [sharing code](https://arc.codes/docs/en/guides/developer-experience/sharing-code) between functions.