The gadget-server package is an auto-generated package of utilities for implementing your Gadget app's backend.
Exports from gadget-server are only available in the backend of your application, and not on the frontend. For reading and writing
data from your frontend, see the @gadgetinc/react package.
This api client has the system-admin role and can perform any action in your Gadget app.
See the API Reference for more information on your app's API and the api client object.
trigger
An instance of the triggers associated with your Gadget app's action. When an action is executed, it receives a trigger object containing information about the event that initiated the action. This object varies depending on the trigger type and includes a type property that specifies the kind of trigger.
api/models/someModel/actions/someAction.js
JavaScript
exportasyncfunctionrun({ trigger }){
// This logs an object providing details about the trigger
An object with utility functions for each of your app's connections to external systems. This object contains pre-configured clients for supported Gadget connections, such as Shopify, OpenAI, and Sentry.
For example, if you wanted to access your OpenAI connection in a Fastify boot plugin, you could do so like this:
If you have a Shopify connection configured, the connections object offers helpers for getting a Shopify API client to make calls to Shopify. All functions that create Shopify API clients create an instance of the client from the shopify-api-node package, pre-configured with the right credentials retrieved from the database.
For example, you can get a Shopify client instance for a given shop ID using connections.shopify.forShopId
Returns an instantiated Shopify API client from shopify-api-node ready for calling the given shop with the given shopId. Retrieves the credentials for this shop by by querying the shopifyShop model under the hood, and using the apiKey and accessToken fields to instantiate the client.
Returns an instantiated Shopify API client from shopify-api-node ready for calling the shop with given myshopifyDomain. Retrieves the credentials for this shop by by querying the shopifyShop model under the hood, and using the apiKey and accessToken fields to instantiate the client.
Returns an instantiated Shopify API client from shopify-api-node ready for calling the shop calling the current action or route, if there is one. The current shop is derived from the trigger running the current action or route. If the current shop is unknown, connections.shopify.current will be undefined.
For more information on calling your backend from your frontend and preserving authentication information, see the Shopify plugin guides.
Allows setting the currently authenticated shop for manually overriding Gadget's Shopify authentication.
Warning: This function is generally not used in the course of normal development with Gadget, as Gadget includes robust for automatically authenticating requests from Shopify as belonging to a particular shop. For frontends using the @gadgetinc/react-shopify-app-bridge library, or building Shopify extensions, Gadget passes headers from the frontend to the backend that securely authenticate shops and populate connections.shopify.current if possible. This function should only be used when you are building your own secure authentication mechanism, and you'd like your code to be able to use connections.shopify.current as you might otherwise.
For more information on calling your backend from your frontend and preserving authentication information, see the Shopify plugin guides.
Returns the contents of the Shopify Session Token passed from the frontend if one was passed. Useful for manually inspecting the session token contents, or accessing the userId for Customer Account extensions that correctly pass a session token.
If you have a BigCommerce connection configured, the connections object offers helpers for getting an API client to make calls to BigCommerce. All functions that create BigCommerce API clients create an instance of the client from the @space48/bigcommerce-api package, pre-configured with the right credentials retrieved from the database.
Returns an instantiated BigCommerce API client from @space48/bigcommerce-api package ready for calling the store calling the current action or route, if there is one. The current store is derived from the trigger running the current action or route. If the current store is unknown, connections.bigcommerce.current will be undefined.
For more information on calling your backend from your frontend and preserving authentication information, see the BigCommerce frontend guide.
Returns an instantiated BigCommerce API client from @space48/bigcommerce-api package ready for calling the given store with the given storeHash. Retrieves the credentials for this store by by querying the bigcommerce/store model under the hood, and using the apiKey and accessToken fields to instantiate the client.
Returns an instantiated BigCommerce API client from @space48/bigcommerce-api package ready for calling the given store with the given bigcommerce/store record. Retrieves the credentials for this store by by querying the bigcommerce/store model under the hood, and using the apiKey and accessToken fields to instantiate the client.
Allows setting the currently authenticated store for manually overriding Gadget's BigCommerce authentication.
Warning: This function is generally not used in the course of normal development with Gadget, as Gadget includes robust for automatically authenticating requests from BigCommerce as belonging to a particular store. For frontends using the @gadgetinc/react-bigcommerce library, Gadget passes headers from the frontend to the backend that securely authenticate stores and populate connections.bigcommerce.current if possible. This function should only be used when you are building your own secure authentication mechanism, and you'd like your code to be able to use connections.bigcommerce.current as you might otherwise.
For more information on calling your backend from your frontend and preserving authentication information, see the BigCommerce plugin guides.
example setting custom authentication using setCurrentStore
2console.log(connections.bigcommerce.current);// undefined for some reason where Gadget can't authenticate the request as coming from a particular store
Returns the user ID of the currently authenticated BigCommerce user stored in the session model, if it is set. Returns undefined otherwise.
connections.openai
If you have configured an OpenAI connection with Gadget, connections.openai is an instance of the official OpenAI JavaScript client for making API calls to all of OpenAI's services. When using Gadget's built-in credentials for OpenAI, only some calls are available, but when using your own credentials, all API functionality is available.
If the record is a new record, this will persist the record and assign it an ID. If the record is an existing record, this will update the database with any changed values from the record.
save will validate the record before persisting it. save persists the record to the database using your app's Internal API.
Returns
Async function, which returns a Promise. Resolves to void. Any encountered validation errors will be thrown.
deleteRecord(record)
Deletes the given record from the database.
models/widget/actions/delete.js
JavaScript
import{ deleteRecord }from"gadget-server";
exportasyncfunctionrun({ record }){
awaitdeleteRecord(record);
}
delete removes the record from your database using your app's Internal API.
Returns
Async function, which returns a Promise. Resolves to void.
applyParams(params, record)
Sets incoming parameters onto a record object.
models/widget/actions/update.js
JavaScript
import{ applyParams }from"gadget-server";
exportasyncfunctionrun({ record }){
applyParams(record);
awaitsave(record);
}
applyParams will set any incoming parameters onto the record. This is useful for updating a record with the parameters from an action or similar call. applyParams does not persist the record -- it just mutates the in-memory record object.
Parameters
params - The data passed to an action from API calls, webhook events, or direct user inputs, which include the fields of a record.
record - Record to apply parameters to.
Returns
Returns void.
Background actions
enqueue(action, input, options)
Enqueues a model or global action to run in the background.
JavaScript
1exportasyncfunctionrun({ record, api }){
2await api.enqueue(
3 api.someModelOrGlobalAction,
4{},
5{id:"background-action-1",priority:"HIGH"}
6);
7}
Parameters
action - Any model or global action.
input - Parameters or data to pass to an action.
options (optional) - Options for governing how a background action is enqueued:
id - A unique identifier to use for the background action. Must be unique among all other background actions within its environment. If not set, a unique ID will be auto-generated and returned.
priority - How high to place this background action in its queue, HIGH priority actions will be executed before default priority actions, and those before LOW priority actions. If not set, the default priority will be used.
queue - A queue to put this background action in that limits the maximum concurrency of all actions in the queue. If not set, the action will go into the global queue, and won't be concurrency limited. For more info on queue options read the reference here.
retries - Configure how many times to retry the action if it fails, and how fast. For more info on the available retry options, see the retries reference.
startAt - The time to start running a background action. The time defined must be formatted as an ISO string.
Returns
Returns void.
queue
queue allows you to place the background action in a dedicated queue and also enables you to control the maximum concurrency of all actions in the queue.
JavaScript
1exportasyncfunctionrun({ record, api }){
2await api.enqueue(
3 api.someModelOrGlobalAction,
4{},
5{
6queue:{
7name:"my-queue",
8maxConcurrency:4,
9},
10}
11);
12}
queue: The name of the queue.
maxConcurrency: The maximum concurrency of all actions in the queue. If not set, the default will be set to 1
retries
retries allows you to configure how fast and how many times to retry the background action if it fails.
retries can be set to an integer to make your background action retry that many times with the default retry schedule, or set to an object to configure exactly how many times and at what rate retries occur.
JavaScript
1exportasyncfunctionrun({ record, api }){
2await api.enqueue(
3 api.someModelOrGlobalAction,
4{},
5{
6retries:{
7retryCount:5,
8maxInterval:60000,
9backoffFactor:2,
10initialInterval:1000,
11randomizeInterval:true,
12},
13// OR simply retries: 5
14}
15);
16}
retryCount: The maximum number of times to retry the operation if it keeps failing. The default is 6.
maxInterval: The maximum amount of time to delay a retry while exponentially backing off. The default is not set, so the retry can backoff indefinitely.
backoffFactor: The exponential backoff factor to use for calculating the retry delay for successive retries. Set this higher to delay longer. The default is 2.
initialInterval: How long to initially delay the first retry, in milliseconds. The default is 1000 ms.
randomizeInterval: Randomizes the delays between attempts by multiplying with a factor between 1 to 2. The default is false.
Enforce that the given record is only accessible by the current shop. For multi-tenant Shopify applications, this is key for enforcing data can only be accessed by the shop that owns it.
4exportasyncfunctionrun({ params, record, logger, api }){
5applyParams(params, record);
6awaitpreventCrossShopDataAccess(params, record);
7awaitsave(record);
8}
For existing records, this function verifies the record object has the same shopId as the shop in the current session, and throws if not.
For new records, this function sets the record's shopId to the current session's shopId.
Parameters
params - Incoming parameters, validated against the current shopId
record - Record to validate or set the shopId on
options:
shopBelongsToField: Picks which belongs to relationship on a model is used for cross-shop validation. Must be the API identifier of a belongs to relationship to the shopifyShop model. If there are multiple relationships to the shopifyShop model on the passed-in record, this is a required parameter
customerBelongsToField: Picks which belongs to relationship on a model is used for cross-customer validation. Must be the API identifier of a belongs to relationship to the shopifyCustomer model. If there are multiple relationships to the shopifyCustomer model on the passed-in record, this is a required parameter
enforceCustomerTenancy: A boolean field that disables cross-customer validation. Defaults to true
Returns
Returns void. Throws if the record is not accessible by the current shop.
finishBulkOperation(record)
Updates the state of a bulkOperation record from Shopify when the operation completes.
models/shopifyBulkOperation/actions/complete.js
JavaScript
1import{ applyParams, save }from"gadget-server";
2import{
3 preventCrossShopDataAccess,
4 finishBulkOperation,
5}from"gadget-server/shopify";
6
7exportasyncfunctionrun({ params, record, logger, api }){
8applyParams(params, record);
9awaitpreventCrossShopDataAccess(params, record);
10awaitfinishBulkOperation(record);
11awaitsave(record);
12}
Parameters
record - The bulkOperation record to update
globalShopifySync(params)
Start running a global Shopify sync for all shops matching the params. This will create a shopifySync record and trigger a sync for each shop.
Parameters
params: The params object for the sync -apiKeys: the list of Shopify APP API keys to trigger a sync for, default: all enabled apps
syncSince: the start date to start syncing data from, default: all time
models: the list of model api identifiers to trigger syncs for, default: all enabled models
force: should Gadget still run actions for records where the updated_at timestamps match
startReason: a string reason to store on the created shopifySync records
returns
Async function. Returns void.
BigCommerce
BigCommerce functions can be imported from gadget-server/bigcommerce.
Enforce that the given record is only accessible by the current store. For multi-tenant BigCommerce applications, this is key for enforcing data can only be accessed by the store that owns it.
For existing records, this function verifies the record object has the same storeId as the shop in the current session, otherwise an Error is thrown.
For new records, this function sets the record's storeId to the current session's bigcommerceStore.
Parameters
params - Incoming parameters, validated against the current storeId
record - Record to validate or set the storeId on
options:
storeBelongsToField: Picks which belongs to relationship on a model is used for cross-shop validation. Must be the API identifier of a belongs to relationship to the bigcommerce/store model. If there are multiple relationships to the bigcommerce/store model on the passed-in record, this is a required parameter
Returns
Returns void. Throws if the record is not accessible by the current shop.
OpenAI
openAIResponseStream
Converts the result returned when making a request using the OpenAI connection with stream: true into a readable stream that Fastify can respond with.
openAIResponseStream must be imported from gadget-server/ai a sub module of gadget-server
Using the openAIResponseStream function to convert an AsyncIterable into a Readable stream
stream - An AsyncIterable containing OpenAI response parts.
returns
A Readable stream with the transformed content from the input stream.
Vite
gadget Vite plugin
gadget() is a Vite plugin that automatically detects the frontend framework type used in the Vite config. The plugin modifies Vite configuration parameters so your app frontend can be run and deployed properly in Gadget.
It is imported from gadget-server/vite.
vite.config.mjs
JavaScript
1importreactfrom"@vitejs/plugin-react-swc";
2import{ defineConfig }from"vite";
3import{ gadget }from"gadget-server/vite";
4
5exportdefaultdefineConfig({
6plugins:[gadget(),react()],
7clearScreen:false,
8});
Currently, the plugin detects if your app frontend is using Remix or Vite + React Router.
This plugin is needed in your Vite config starting framework version 1.2.
Injected configuration
The gadget() plugin injects the following configuration into your Vite config, depending on the frontend framework type detected:
Vite + React Router config
The following configuration is injected into your Vite config while developing:
gadget() output - Vite + React Router - developing
json
1{
2"build":{
3"manifest":true,
4"outDir":"./.gadget/vite-dist",
5"emptyOutDir":true
6}
7}
When building for production, the following configuration is outputted:
gadget() output - Vite + React Router - building production bundle
Gadget provides pre-defined Remix configuration in remixViteOptions to help set up your Vite app to work with Remix.
It is imported from gadget-server/remix.
vite.config.mjs
JavaScript
1import{ defineConfig }from"vite";
2import{ gadget }from"gadget-server/vite";
3import{ remixViteOptions }from"gadget-server/remix";// import the pre-defined config
4import{ vitePlugin as remix }from"@remix-run/dev";
5
6exportdefaultdefineConfig({
7plugins:[
8gadget(),
9remix({
10...remixViteOptions,// pass the config to the remix plugin
11}),
12],
13});
remixViteOptions contains the following configuration:
remixViteOptions
json
{
"buildDirectory":".gadget/remix-dist/build",
"appDirectory":"web"
}
We upload and serve the bundled Remix files inside the .gadget/remix-dist/build directory, so we need to specify the buildDirectory value from Remix.
appDirectory references the directory containing your frontend files, which is web by default.
Check out the Remix documentation for more information about these parameters.
Action Contexts
Each Action and Global Action is passed a context object as its first and only argument. This context object contains all the inputs necessary for running an action, as well as some utilities.
The context object is usually destructured in the run or onSuccess function arguments with curly braces:
A connected, authorized instance of the generated API client for the current Gadget application. See the API Reference for more details on this object's interface
params
Record<string, any>
The incoming data from the API call invoking this action
record
GadgetRecord<Model>
The record this action is operating on. Only available in Model Actions, and not available in Global Actions.
session
Session
A record representing the current user's session, if there is one
config
Record<string, string>
An object of all the environment variables created in Gadget's Environment Variables editor
connections
Connections
An object containing client objects for all connections. Read the connections guide to see what each connection provides
An object describing the incoming HTTP request, if this action was triggered by an HTTP request
Exported Types
The gadget-server package contains TypeScript types specific to your application, generated from your app's models and fields. This gives great type safety where your actions and routes can import a specific type that describes the required inputs and output.
Actions
gadget-server exports a type for each Action's context argument, which is the data passed to the run or onSuccess function.
The context type is named <Action><Model>ActionContext, where <action> is the capitalized name of your action, and <model> is the capitalized name of your model. For example, if you have an action named create on a model named `user, you can import the type for that action like this:
gadget-server exports a type for each Global Action's context argument, which is the data passed to the run or onSuccess function.
The context type is named <Action>GlobalActionContext, where <action> is the capitalized name of your Global Action. For example, if you have a Global Action named flipWidgets, you can import the type for that action like this:
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.
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"
}
RequestData
The RequestData type describes an incoming HTTP request being processed by an Action.
Note: The RequestData object is passed to Actions and Global Actions, and is a read-only view of the incoming request. This is different than the Request object passed to HTTP Route handlers which has more properties only available in HTTP routes.
Properties
ip: the requesting client's IP (also known as the x-forwarded-for header in other systems)
url: the requested URL (usually /api/graphql)
method: the HTTP request method, like GET, POST, etc
userAgent: the passed user agent string for this request
headers: a map of strings to strings or string arrays describing each incoming request header
id: a unique identifier assigned to this request by Gadget, used for logging and available in the x-request-id response header
JavaScript
exportasyncfunctionrun({ api, request,...rest }){
console.log(request.ip);// log the IP of the client making this request
}
Route handlers
Route context
All route handlers registered in HTTP Routes are passed a context object as their first and only argument:
Context key
Description
request
the Request object describing the incoming HTTP request
a connected, authorized instance of the generated API client for the current Gadget application. See the API Reference for more details on this object's interface.
applicationSession
a record representing the current user's session, if there is one.
applicationSessionID
the ID of the record representing the current user's session, if there is one.
connections
an object containing client objects for all connections. Read the connections guide to see what each connection provides.
logger
a logger object suitable for emitting log entries viewable in Gadget's Log Viewer.
config
an object of all the environment variables created in Gadget's Environment Variables editor.
currentAppUrl
the current url for the environment. e.g. https://my-app.gadget.app
request
The request object passed in the route context describes the incoming HTTP request, with properties for accessing the HTTP request headers, the request body, the matched route, and more. request is powered by Fastify, a high-performance HTTP framework for nodejs.
Request objects have the following fields:
FastifyRequest field
Description
query
the parsed query string from the incoming request, its format is specified by the route's querystringParser
body
the request payload, see Content-Type Parser for details on what request payloads Fastify natively parses and how to support other content types
params
the params matching the URL
headers
the headers getter and setter
method
the HTTP method for the route, like GET, POST, or DELETE
raw
the incoming HTTP request from Node core
id
the request ID
log
a logger instance for the incoming request
ip
the IP address of the incoming request
hostname
the host of the incoming request (derived from X-Forwarded-Host header when the trustProxy option is enabled). For HTTP/2 compatibility it returns :authority if no host header exists.
protocol
the protocol of the incoming request (will always be https on Gadget)
method
the method of the incoming request
url
the URL of the incoming request
routerMethod
the method defined for the router that is handling the request
routerPath
the path pattern defined for the router that is handling the request
is404
true if the request is being handled by a 404 error handler, false if it is not
socket
the underlying connection of the incoming request
routeSchema
the scheme definition set for the router that is handling the request
routeConfig
the route config object
routeOptions
the route option object passed when defining the route
bodyLimit
either the server-wide limit or route-specific limit on the size of the request body
url
the path of the URL to match this route
logLevel
log level defined for this route
version
a semver-compatible string that defines the version of the endpoint
exposeHeadRoute
creates a sibling HEAD route for any GET routes
prefixTrailingSlash
string used to determine how to handle passing / as a route with a prefix.
The reply object passed to each route in the context has functions for setting up and sending an HTTP response from your server for your route. The object is a FastifyReply object from Fastify, a high-performance HTTP framework for nodejs.
Reply objects have these functions and properties:
Reply property
Description
code(statusCode)
sets the status code
status(statusCode)
an alias for .code(statusCode)
statusCode
read and set the HTTP status code
header(name, value)
sets a response header
headers(object)
sets all the keys of the object as response headers
getHeader(name)
retrieve the value of an already set header
getHeaders()
gets a shallow copy of all current response headers
removeHeader(key)
remove the value of a previously set header
hasHeader(name)
determine if a header has been set
trailer(key, function)
sets a response trailer
hasTrailer(key)
determine if a trailer has been set
removeTrailer(key)
remove the value of a previously set trailer
type(value)
sets the header Content-Type
redirect([code,] dest)
redirect to the specified URL with an optional status code. If not provided, the status code defaults to 302
callNotFound()
invokes the custom not found handler
serialize(payload)
serializes the specified payload using the default JSON serializer or using the custom serializer (if one is set) and returns the serialized payload
serializer(function)
sets a custom serializer for the payload
send(payload)
sends the payload to the user, could be a plain text, a buffer, JSON, stream, or an Error object
sent
a boolean value that you can use if you need to know if send has already been called
LoggerInstance is a high performance alternative to console.log which is optimized for use in production. console.log logs will still appear in your Log Viewer but are not recommended for use in production.
The default log levels (and associated log functions) are trace, debug, info, warn, error, and fatal.
An object can optionally be supplied as the first parameter to log messages. Each key and value of the object is stringified and written to your application's logs as JSON.
JavaScript
logger.info({value:{foo:"bar"}});
Log calls at any level can also pass Error objects to get an easy-to-digest log entry in the Log Viewer for the error, including its stack trace and any other associated details. To log Error objects, pass the object at the error key of the structured data: