Build a full-stack single-click search keyword app for BigCommerce
Expected time: 25 minutes
This tutorial will show you how to build a full-stack, single-click app for BigCommerce.
Adding appropriate search keywords to products is important so shoppers can find exactly what they are looking for when shopping on BigCommerce storefronts. This app will allow merchants to enter keywords, check to see if those keywords exist in product descriptions, and add them as search_keywords on products.
By the end of this tutorial, you will have:
Set up a BigCommerce connection
Subscribed to BigCommerce webhooks
Stored BigCommerce data in a Gadget database
Built a complete serverless Node.js backend
Used the BigDesign library to build a React frontend
(Optional) Sync historical product data from BigCommerce
Prefer a video?
Prefer a video?
If you prefer video tutorials, you can build along with our video on Youtube.
Copy the Auth callback URL and Load callback URL from Gadget to your BigCommerce app.
Select the Products Modify OAuth scope and click Update & Close in the BigCommerce app.
In the BigCommerce Developer Portal, click View Client ID for your new app and copy the Client ID and Client Secret to Gadget, then click Continue.
In your BigCommerce sandbox store, navigate to Apps → My Draft Apps, hover over your newly added app, click Learn more.
Click Install.
We now have a full-stack, single-click BigCommerce app in our store control panel! OAuth and frontend sessions are handled, and we can subscribe to BigCommerce webhooks.
Step 2: Create data models for products and search keywords
We need to store both product data and search keywords entered by merchants in our Gadget database. We can create data models in Gadget to store this data.
Right-click on the api/models/bigcommerce directory in the Gadget file tree and select Add model.
Name the model product and add the following fields and validations:
Field name
Field type
Validations
bigcommerceId
number
Uniqueness, Required
name
string
Required
description
string
searchKeywords
string
store
belongs to
Required
type
enum (with options: digital & physical)
Required
weight
number
Required
price
number
Required
For the store field, select the bigcommerce/store model as the parent model, so that bigcommerce/storehas manybigcommerce/product.
For the type field, add the following options: physical and digital.
bigcommerceId uniqueness validation
For multi-tenant apps, you may have multiple stores whose resources have the same bigcommerceId. To avoid conflicts, you can scope the
Uniqueness validation on bigcommerceId by the store relationship. This ensures that bigcommerceId is unique per store.
Click the + button next to api/models to create another new model. (Note: this will create a new model outside of the bigcommerce namespace.)
Name the model searchKeyword and give it the following field and validations:
Field name
Field type
Validations
value
string
Uniqueness, Required
We have successfully set up our data models! This also generated a CRUD (Create, Read, Update, Delete) API for each model that we can use to interact with our data.
Why store product data?
Product data needs to be stored to avoid webhook looping on store/product/updated webhooks. If
no data is stored, change detection cannot be used to see if a product must be updated.
Step 3: Subscribe to store/product webhooks
Now we can subscribe to webhooks and use them to run some code that will check for stored search keywords in product descriptions. If a keyword is found, we will write that keyword back to the product in BigCommerce.
Click the + button next to api/actions and enter bigcommerce/handleProductWebhooks.js. This creates a bigcommerce namespace folder and our new action.
Click the + button in the action's Triggers card and select BigCommerce.
Select the store/product/created, store/product/updated, and store/product/deleted webhook scopes.
(Optional) Remove the Generated API endpoint trigger from the action.
Now this action will run anytime a product is created, updated, or deleted in BigCommerce!
When a product webhook is fired, we want to call the bigcommerce/product model's actions to create, update, or delete records in the Gadget database.
Notice that the upsert meta API is used to handle store/product/updated webhooks. This is
because the product may not yet exist in our database if we haven't synced historical data.
Paste the following code in api/actions/bigcommerce/handleProductWebhooks.js:
56// upsert the product into the database, using the bigcommerceId as the key identifier
57await api.bigcommerce.product.upsert({
58...productToSave,
59on:["bigcommerceId","store"],
60});
61break;
62}
63}else{
64thrownewError(`Product ${params.id} not found in BigCommerce store!`);
65}
66};
67
68exportconstoptions:ActionOptions={
69triggers:{
70api:false,
71bigcommerce:{
72webhooks:[
73"store/product/created",
74"store/product/updated",
75"store/product/deleted",
76],
77},
78},
79};
This will handle the product webhook topics and call the required bigcommerce/product action.
Action parameters
Gadget actions have a high-context parameter that provides you with everything you need to interact with the rest of your app.
In this example, we use:
params to get the product ID from the webhook payload
api to call our app's API and interact with our database
connections to get the BigCommerce API client
trigger to read the webhook topic
logger to write to Gadget's built-in Logs tool
Step 4: Write search keywords back to BigCommerce
When a product is created or updated in BigCommerce, we want to check the product description for search keywords. If a keyword is found, we will write it back to the product in BigCommerce.
We want to run this code when we create a new product or update an existing product. We can create a utility function to handle this logic and call it from our create and update actions.
Create a utils.js file in the api/models/bigcommerce/product directory.
1import{ActionOptions, applyParams, save }from"gadget-server";
2import{ getKeywords }from"../utils";
3
4exportconst run:ActionRun=async({ params, record })=>{
5applyParams(params, record);
6awaitsave(record);
7};
8
9exportconst onSuccess:ActionOnSuccess=async({ record })=>{
10if(
11 record.storeId&&
12 record.description&&
13 record.description!==""&&
14 record.changed("description")
15){
16awaitgetKeywords({
17...record,
18 storeId: record.storeId,
19 description: record.description,
20});
21}
22};
23
24exportconst options:ActionOptions={
25 actionType:"update",
26};
1import{ActionOptions, applyParams, save }from"gadget-server";
2import{ getKeywords }from"../utils";
3
4exportconstrun:ActionRun=async({ params, record })=>{
5applyParams(params, record);
6awaitsave(record);
7};
8
9exportconstonSuccess:ActionOnSuccess=async({ record })=>{
10if(
11 record.storeId&&
12 record.description&&
13 record.description!==""&&
14 record.changed("description")
15){
16awaitgetKeywords({
17...record,
18storeId: record.storeId,
19description: record.description,
20});
21}
22};
23
24exportconstoptions:ActionOptions={
25actionType:"update",
26};
We have subscribed to webhooks and are writing data back to BigCommerce! Now we can build a frontend to allow merchants to enter search keywords.
Additional action info
We make use of the same high-context parameters in the create and update actions as we did in the webhook-handling global action. This allows us to interact with the database, BigCommerce API, and logger.
One key difference in model actions is that we also have a record parameter, which is the record being created or updated. In this case, it is our current bigcommerce/product record.
Step 5: Grant merchants API access to search keywords
All Gadget apps have authorization built in. A role-based access control system allows us to restrict API and data access to merchants and unauthenticated shoppers. Merchants won't have access to data stored in your custom models by default. We need to grant them access to our actions to be able to call them from our frontend.
Navigate to the accessControl/permissions page.
Grant the bigcommerce-app-users role access to the searchKeyword/ model's read, create, and delete actions.
The bigcommerce-app-users role is automatically assigned to merchants who install your app in BigCommerce. You can read more about the role in the docs.
Step 6: Build a React frontend with the BigDesign library
We've finished building our database and backend, now we just need a frontend that allows merchants to enter search keywords.
The BigDesign library is pre-installed in Gadget and can be used to build a React frontend for single-click apps.
Replace the code in web/routes/index.jsx with the following:
Gadget provides the @gadgetinc/react library which contains useful hooks and tools for building React frontends. The
useFindMany, useAction, and useActionForm hooks are used to fetch data, call actions, and manage form state, respectively.
Test it out!
Now we can test our app by going back to our app in the sandbox store control panel and entering some search keywords. As we do this, the keywords will be stored in our Gadget database.
Once one or more keywords have been added, create a new product in your BigCommerce store and add one or more of the stored keywords to the product description. The keywords should be written back to the product in BigCommerce! You will need to refresh the product page in BigCommerce to see the changes.
Congrats! You have just built a full-stack, single-click app for BigCommerce in Gadget!
Step 7 (Optional): Sync historical product data from BigCommerce
Our app works great for new or updated products, but what about the products that were already in the store before we installed the app? We can sync historical product data from BigCommerce to our Gadget database to ensure that all products have search keywords.
The bigcommerce/store model has an install.js action that runs when the app is installed. We can use this action to fetch all products from BigCommerce and enqueue a background action to create them in Gadget.
Add the following code to api/models/bigcommerce/store/install.js:
api/models/bigcommerce/store/install.js
JavaScript
1import{ActionOptions, applyParams, save }from"gadget-server";
2
3exportconst run:ActionRun=async({ params, record })=>{
Now when you install your app on a sandbox store, all products will be synced to your Gadget database, and search keywords will be added to the products in BigCommerce!
To test this code out, you can:
Uninstall your app from your sandbox store.
In the Gadget command palette, run Bulk reset model data and uncheck the searchKeyword model so that your searchKeyword records are not deleted!