Shopify / shopify-app-template-remix

378 stars 152 forks source link

How to create custom cli script to access shopify and prisma? #551

Open cnkt opened 9 months ago

cnkt commented 9 months ago

Issue summary

Could we get some documentation or a brief explanation of how to integrate a custom JS (or TS) file and access prisma and shopify variables which are exported from shopify.server.ts and db.server.ts? I am asking this because I need to create a cron-job to fetch products for stores using my apps. I need to create a cli script for that.

Thanks!

lizkenyon commented 9 months ago

Hi there 👋

I agree this would be valuable documentation to have. The team will work on getting something up.

rmortes commented 9 months ago

Currently facing a similar problem. If you've solved I'd like to know how

rmortes commented 9 months ago

From testing, and the behavior noted in this test, I figured out that an admin context can be extracted with the method shopify.unauthenticated.admin as long as you have access to the shopify variable in shopify.server.js.

// shopify.server.js

// Example code
setTimeout(async () => {
  const { admin, session } = await shopify.unauthenticated.admin("store-domain.myshopify.com")
  console.log(await admin.rest.resources.Product.count({ session }));
}, 1000);

const shopify = shopifyApp({
  ...
})

In my particular use-case the domain is constant, since is an app for a particular customer, but in case it wasn't, you could query the prisma database for the stores. The model contains a "shop", which is the shop URL and can be used in shopify.unauthenticated.admin as long as the access token is still valid.

cnkt commented 9 months ago

In our particular case we can't touch the remix related files. So we solved it like that:

After running the app with npm run dev we call npm run shopify app env pull. It will create an .env file with content like that:

SHOPIFY_API_KEY=
SHOPIFY_API_SECRET=
SCOPES=write_products

(with your real key and secret)

After that I added the dotenv library to project so I can read these values. Lastly here is my file which doesn't need Remix related things to access prisma and shopify:


import "dotenv/config";
import prisma from "./db.server";
import { createAdminApiClient } from "@shopify/admin-api-client";
import { LATEST_API_VERSION } from "@shopify/shopify-api";

async function main() {
  const ses = await prisma.session.findFirst();

  if (null === ses) {
    return;
  }

  const client = createAdminApiClient({
    storeDomain: ses.shop,
    apiVersion: LATEST_API_VERSION,
    accessToken: ses.accessToken,
  });

  const operation = `
  query ProductsQuery {
    products(first: 10) {
      edges {
        node {
          id
          title
          description
        }
      }
    }
  }
`;

  const { data, errors, extensions } = await client.request(operation, {
    variables: {},
  });

  console.log(data, errors, extensions);
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });

I just added this line to scripts part of package.json and that's it. Done :)

"fetch-products": "npx ts-node ./app/cli-command.server.ts",

Now you can call it like npm run fetch-products

But of course I'm not happy with that. If there is a more "best practice" method I'm happy to learn it.