Get Started with Tento
Build by drizzle team
Tento - is simple yet powerful API for working with Shopify data, including metaobjects, metafields and products.
It also provides a CLI tool for two-way synchronization between your local schema definition and Shopify.
This guide assumes familiarity with:
@shopify/shopify-api - package for access for the Shopify Admin API - read here
dotenv - package for managing environment variables - read here
tsx - package for running TypeScript files - read here
Understanding of Shopify Metaobject instance - read here
Understanding of Shopify Metafield instance - read here
Get started with OAuth - read here
Migrations tento.config.ts
fundamentals - read here
Step 1 - Install dependencies
npm i @drizzle-team/tento
yarn add @drizzle-team/tento
pnpm add @drizzle-team/tento
bun add @drizzle-team/tento
Step 2 - Setup connection variables
Create a .env
file in the root of your project and add your Shopify Access Token variable:
SHOPIFY_ACCESS_TOKEN=
SHOPIFY_SHOP_ID=
Step 3 - Declare schema file
Create a schema.ts
file and declare your metaobjects and metafields schema:
info
As of now Tento only supports one schema file.
import { metaobject , metafield } from '@drizzle-team/tento' ;
export const description = metafield ({
name : "Description" ,
key : "description" ,
namespace : "custom" ,
ownerType : "PRODUCT" ,
fieldDefinition : (f) => f .multiLineTextField () ,
});
export const designer = metaobject ({
name : "Designer" ,
type : "designer" ,
fieldDefinitions : (f) => ({
name : f .singleLineTextField ({
name : "Title" ,
required : true ,
validations : (v) => [ v .min ( 1 ) , v .max ( 50 )] ,
}) ,
description : f .multiLineTextField ({
name : "Description" ,
}) ,
website : f .url ({
name : "Website" ,
}) ,
}) ,
});
Step 4 - Connect Tento client
Create a index.ts
file and initialize the connection:
import 'dotenv/config' ;
import '@shopify/shopify-api/adapters/web-api' ;
import * as schema from './db/schema' ;
import { createClient , tento } from '@drizzle-team/tento' ;
const client = tento ({
client : createClient ({
shop : process . env . SHOPIFY_SHOP_ID ! ,
headers : {
"X-Shopify-Access-Token" : process . env . SHOPIFY_ACCESS_TOKEN ! ,
} ,
}) ,
schema ,
});
Step 5 - Setup Tento config file
Tento config - a configuration file that is used by Tento CLI and contains all the information about your Shopify connection and schema files.
Create a tento.config.ts
file in the root of your project and add the following content:
import 'dotenv/config' ;
import { defineConfig } from "@drizzle-team/tento/cli" ;
export default defineConfig ({
schemaPath : './src/schema.ts' ,
shop : process . env . SHOPIFY_SHOP_ID ! ,
headers : {
'X-Shopify-Access-Token' : process . env . SHOPIFY_ACCESS_TOKEN ! ,
} ,
});
Step 6 - Applying changes to the Shopify
You can directly apply changes to your Shopify store using the tento push
command, or using client method applySchema()
:
npx tento push
import 'dotenv/config' ;
import '@shopify/shopify-api/adapters/web-api' ;
import * as schema from './db/schema' ;
import { createClient , tento } from '@drizzle-team/tento' ;
const client = tento ({
client : createClient ({
shop : process . env . SHOPIFY_SHOP_ID ! ,
headers : {
"X-Shopify-Access-Token" : process . env . SHOPIFY_ACCESS_TOKEN ! ,
} ,
}) ,
schema ,
});
async function main () {
await client .applySchema ();
}
main ();
Read more about migration process in documentation .
Step 7 - Query the Shopify
Let’s update the src/index.ts
file with queries to create, read, update, and delete designers
import 'dotenv/config' ;
import '@shopify/shopify-api/adapters/web-api' ;
import * as schema from './db/schema' ;
import { createClient , tento } from '@drizzle-team/tento' ;
const client = tento ({
client : createClient ({
shop : process . env . SHOPIFY_SHOP_ID ! ,
headers : {
"X-Shopify-Access-Token" : process . env . SHOPIFY_ACCESS_TOKEN ! ,
} ,
}) ,
schema ,
});
async function main () {
await client .applySchema ();
const designer : typeof client . metaobjects . designer .$inferInsert = {
name : "John" ,
description : "John is designer" ,
website : "" ,
};
const createdDesigner = await client . metaobjects . designer .insert (designer);
console .log ( "New designer created!" );
const designers = await client . metaobjects . designer .list ({
first : 50
});
console .log ( 'Getting first 50 designers from the Shopify: ' , designers)
/*
const designers: {
items: {
_id: string;
_handle: string;
_displayName: string;
_updatedAt: Date;
name: string;
description: string | null;
website: string | null;
}[];
pageInfo: {
startCursor: string;
endCursor: string;
hasNextPage: boolean;
hasPreviousPage: boolean;
};
}
*/
await client . metaobjects . designer .update ( createdDesigner ._id , {
fields : {
description : "John is designer!" ,
} ,
});
console .log ( "Designer info updated" );
await client . metaobjects . designer .delete ( createdDesigner ._id);
console .log ( "Designer deleted" );
}
Step 8 - Run index.ts file
To run any TypeScript files, you have several options, but let’s stick with one: using tsx
You’ve already installed tsx
, so we can run our queries now
Run index.ts
script
npx tsx src/index.ts
yarn tsx src/index.ts
pnpm tsx src/index.ts
bun tsx src/index.ts