Triggers 

What is a trigger? 

Triggers in Gadget are events or conditions that initiate an Action within an application. They parse external events, such as incoming webhooks or API calls, and transmit them to the rest of the Action. Default triggers are already established in many Actions, such as the GraphQL API trigger for integrating the Action into your app's API or the Shopify Webhook trigger that executes Actions in response to Shopify webhooks.

Types of triggers 

GraphQL API trigger 

The GraphQL API trigger in Gadget enables the invocation of actions through the GraphQL API generated for your application. Each action associated with a GraphQL API trigger is represented by a corresponding mutation. When this mutation is triggered, the action is executed, and the resulting record or errors are returned by the GraphQL API. These mutations can be easily called from the JavaScript client of your application, providing a convenient and straightforward way to interact with and trigger actions through the GraphQL API.

For example, if we add a publish action to a Post model in the Gadget editor, the GraphQL API will get a new publishPost mutation:

GraphQL
1mutation PublishPost($id: GadgetID!, $post: PublishPostParams!) {
2 publishPost(id: $id, post: $post) {
3 success
4 errors {
5 message
6 }
7 post {
8 id
9 title
10 publishedAt
11 }
12 }
13}

You can also call the publishPost mutation with the generated JS client in a JS script:

JavaScript
import { Client } from "@gadget-client/blog-post-example";
const client = new Client();
await client.post.publish(123, { post: { publishedAt: new Date() } });

Or call the mutation from a React app using the @gadgetinc/react hooks library:

JavaScript
1import { useAction } from "@gadgetinc/react";
2import { api } from "../api"; // some file which instantiates the Client
3
4export const CreatePost = (props) => {
5 const [{ data, fetching, error }, act] = useAction(api.post.publish);
6
7 if (fetching) {
8 return <div>Saving...</div>;
9 }
10
11 if (error) {
12 return <div>Error: {error.message}</div>;
13 }
14
15 return (
16 <button
17 onClick={() => {
18 act(123, { post: { publishedAt: new Date() } });
19 }}
20 >
21 Publish Post
22 </button>
23 );
24};

Scheduler trigger 

You can use the scheduler trigger if you want to run your action on a regular schedule, similar to scheduling a cron job. For example, perhaps you would like to fetch some data from another service every hour or summarize your Gadget data every Thursday at midnight. Every Global Action is allowed to have one scheduler trigger, which you can add by clicking the plus icon next to the triggers panel:

Configuring a scheduler trigger

When you add the scheduler trigger card above your code file, you will be able to change the schedule or add more entries to the schedule. For example, you will need five entries - one for each day - to have a schedule that runs at 4 PM every weekday.

The scheduler trigger does not prevent duplicate calls from overlapping schedule items. For example, if you have a schedule with one entry that runs every hour, on the hour, and another entry for every day at 5:00 PM, your action will run twice every day at 5:00 PM.

Since the scheduler trigger executes a Global Action like the API, all logs emitted from the Action can be found in the log viewer.

Any execution of a scheduled Global Action that overlaps a previously scheduled execution that is still running will be ignored. For example, suppose you have a schedule that runs a Global Action every minute. If an execution at 10:50 takes 3.5 minutes to run, the executions that were scheduled for 10:51, 10:52, and 10:53 will be ignored, and the next scheduled execution of the Global Action will be at 10:54. Any execution that fails will be retried 4 times, so a maximum of 5 attempts. Similar to overlapping executions, retries will also cause overlapping scheduled executions to be ignored.

The Scheduler trigger supports invoking your Global Actions using a cron expression. To use a cron expression, select the cron option in the interval list, and enter a valid cron expression. Like the other interval types, cron expressions are additive, where multiple cron expressions will be combined to create the schedule.

For more on cron expressions, see https://crontab.guru.

Webhook trigger 

Webhook triggers in Gadget provided from Shopify is dependent on establishing a Shopify connection. Once the connection is set up, Gadget can receive webhooks sent by Shopify. When Gadget receives a webhook from Shopify, it performs an authenticity verification process and triggers the corresponding Action associated with the webhook.

The complete payload of the webhook received from Shopify is accessible within the trigger object that is passed to your Action code. This allows you to access and utilize the entire webhook payload data within your Action's logic and processing.

Webhook retries 

If the Action fails for any reason, Gadget will retry up to 10 times with an increasing delay between each attempt.

The same traceId is used for each retry. This traceId can be used to filter a Gadget app's Logs to see details about each attempt, for example, {environment_id="123"} | json | level=~"warn|error" | trace_id="21a0324a67729a47ded4b33046afcffe".

If the Action fails on the last attempt, the webhook is "lost," but your next daily sync should ensure that the affected records in Gadget are brought back in sync with Shopify.

Shopify sync trigger 

In order to maintain data synchronization with Shopify, relying solely on webhooks is not sufficient. To adhere to Shopify's best practices, most Shopify models in Gadget also receive a sync trigger.

This sync trigger is responsible for reconciling any missed webhooks and ensuring data is kept up to date. The sync process runs once a day and serves two primary purposes. Firstly, it ensures that any data from missed webhooks within the past day is captured and integrated into the Gadget system, thus keeping the data up to date. Secondly, it guarantees that models that do not receive webhooks directly are still updated and synchronized with the latest information.

By incorporating the sync trigger, Gadget ensures that data consistency is maintained and any gaps or missed updates are addressed on a daily basis, aligning with Shopify's recommended approach for data synchronization.

Actions that fail during sync are not retried. You can visit the Shopify Connection page to find the failed sync and view the logs for that sync.

Trigger descriptors 

Each action is passed a trigger object that contains information related to what event triggered the action to run. The trigger object is different for each type of trigger that can call an action and has a type object describing which type of trigger fired.

models/someModel/someAction.js
JavaScript
export async function run({ api, record, trigger }) {
console.log(trigger); // will log an object like { "type": "api", "rootModel": "someModel", "rootAction": "someAction", etc ... }
}

api trigger 

api triggers describe calls to your Gadget app's GraphQL API, like those made by the JS client or in the GraphQL playground.

An example API trigger
json
1{
2 "type": "api",
3 "mutationName": "updateWidget",
4 "rootModel": "widget",
5 "rootAction": "update",
6 "rawParams": {
7 "id": "123",
8 "widget": {
9 "title": "New Widget Title",
10 "inventoryCount": 10
11 }
12 }
13}

Properties

  • type: will always be set to "api"
  • mutationName: the string name of the mutation called in the API
  • rootModel: the API identifier of the Model the mutation was called on. Can be different than the root-level model when invoking Nested Actions. Is not set for Global Actions.
  • rootAction: the API identifier of the Action triggered by the mutation. Can be different than the root-level action when invoking Nested Actions.
  • rawParams: the params passed to this API call, including any data for nested actions if passed

scheduler trigger 

scheduler triggers describe actions invoked by the built-in Scheduler within Gadget. No other data is currently passed with this type of trigger.

json
{
"type": "scheduler"
}

shopify_sync trigger 

shopify_sync triggers describe actions run by Gadget's Shopify Sync, including daily syncs and manual syncs.

An example Shopify Sync trigger
json
1{
2 "type": "shopify_sync",
3 "shopId": "123456",
4 "apiVersion": "2023-01",
5 "shopifyScopes": ["read_products", "write_products"],
6 "syncId": "1",
7 "syncSince": null,
8 "models": ["shopifyShop", "shopifyProduct"],
9 "force": false,
10 "startReason": undefined // will be "scheduled" if Action ran via daily sync
11}

Properties

  • type: will always be set to "shopify_sync"
  • shopId: the identifier of the Shopify shop being synced
  • apiVersion: the version of the Shopify API being used for the sync
  • shopifyScopes: the available OAuth scopes of the Shopify shop being synced
  • syncId: the identifier of the sync record tracking the state of this sync (optional, only available if set)
  • syncSince: the specified date range of this sync (optional, only set if specified when the sync was started)
  • models: the list of model API identifiers that this sync will work on
  • force: indicates if this sync is being run in 'force' mode, which will always run actions even if the 'updated_at' timestamps match between Gadget and Shopify
  • startReason: the string describing the reason why this sync was started (optional, only set if specified when the sync began)

shopify_webhook trigger 

shopify_webhook triggers describe actions that occur in response to Shopify webhooks, such as 'products/update' or 'orders/create'.

json
1// An example Shopify Webhook trigger
2{
3 "type": "shopify_webhook",
4 "topic": "products/update",
5 "payload": {
6 "id": 788032119674292900,
7 "title": "Example T-Shirt",
8 "body_html": "An example T-Shirt",
9 "vendor": "Acme",
10 "product_type": "Shirts",
11 "created_at": null,
12 "handle": "example-t-shirt"
13 // ... etc matching Shopify's format exactly
14 },
15 "shopId": "shop123",
16 "retries": 0
17}

Properties

  • type: will always be set to "shopify_webhook"
  • topic: the string representing the topic of the incoming webhook from Shopify, like products/update or orders/create
  • payload: the raw incoming payload from Shopify, which includes all the data sent by the webhook unchanged
  • shopId: the identifier for the Shopify store that received the webhook
  • retries: the number of times this webhook has been retried

shopify_oauth trigger 

shopify_oauth triggers describe actions invoked during the installation of an app through the Shopify Partners connection process. No other data is currently passed with this type of trigger.

json
{
"type": "shopify_oauth"
}

shopify_admin trigger 

shopify_admin triggers describe actions invoked during the installation of a Shopify app provisioned in the Shopify Admin. No other data is currently passed with this type of trigger.

json
{
"type": "shopify_admin"
}