Shopify CLI with REST API

Topic summary

Main issue: A React/Node app scaffolded with Shopify CLI successfully uses GraphQL for queries/mutations, but the author needs to fetch “pages,” which they note is only available via Shopify’s REST API and asks for an example of calling REST from a Shopify CLI app.

Context provided:

  • Backend middleware shows session verification and a test GraphQL query using Shopify.Clients.Graphql to confirm OAuth.
  • Frontend uses Apollo Client’s useQuery to fetch products via GraphQL, with code demonstrating a products query.

Technical notes:

  • Shopify CLI scaffolds the app; GraphQL is integrated via Shopify’s Node API library and Apollo Client.
  • “Pages” resource is described as REST-only by the author, prompting need for REST calls.

Status and outcomes:

  • No solution or example for REST calls is provided in the thread yet.
  • No decisions or action items; request remains unresolved/ongoing.

Important artifacts: Code snippets are central to understanding the current GraphQL setup and the integration point where a REST example is sought.

Summarized with AI on February 18. AI used: gpt-5.

I’ve created a React/Node Shopify app via Shopify CLI
With the tutorials, I can query data and mutate data with GraphQL
But I want to query “pages” which only available with RestAPI
Anyone having example Call Rest API with Shopify CLI ?

Below are my shopify CLI config for GraphQL and how I using GraphQL to query data

import { Shopify } from "@shopify/shopify-api";

const TEST_GRAPHQL_QUERY = `
{
  shop {
    name
  }
}`;

export default function verifyRequest(app, { returnHeader = true } = {}) {
  return async (req, res, next) => {
    const session = await Shopify.Utils.loadCurrentSession(
      req,
      res,
      app.get("use-online-tokens")
    );

    let shop = req.query.shop;

    if (session && shop && session.shop !== shop) {
      // The current request is for a different shop. Redirect gracefully.
      return res.redirect(`/auth?shop=${shop}`);
    }

    if (session?.isActive()) {
      try {
        // make a request to make sure oauth has succeeded, retry otherwise
        const client = new Shopify.Clients.Graphql(
          session.shop,
          session.accessToken
        );
        await client.query({ data: TEST_GRAPHQL_QUERY });
        
        return next();
      } catch (e) {
        if (
          e instanceof Shopify.Errors.HttpResponseError &&
          e.response.code === 401
        ) {
          // We only want to catch 401s here, anything else should bubble up
        } else {
          throw e;
        }
      }
    }

    if (returnHeader) {
      if (!shop) {
        if (session) {
          shop = session.shop;
        } else if (Shopify.Context.IS_EMBEDDED_APP) {
          const authHeader = req.headers.authorization;
          const matches = authHeader?.match(/Bearer (.*)/);
          if (matches) {
            const payload = Shopify.Utils.decodeSessionToken(matches[1]);
            shop = payload.dest.replace("https://", "");
          }
        }
      }

      if (!shop || shop === "") {
        return res
          .status(400)
          .send(
            `Could not find a shop to authenticate with. Make sure you are making your XHR request with App Bridge's authenticatedFetch method.`
          );
      }

      res.status(403);
      res.header("X-Shopify-API-Request-Failure-Reauthorize", "1");
      res.header(
        "X-Shopify-API-Request-Failure-Reauthorize-Url",
        `/auth?shop=${shop}`
      );
      res.end();
    } else {
      res.redirect(`/auth?shop=${shop}`);
    }
  };
}
import { gql, useQuery } from "@apollo/client";
import { Page, Layout, Banner, Card } from "@shopify/polaris";
import { Loading } from "@shopify/app-bridge-react";
import { ProductsList } from "./ProductsList";
// GraphQL query to retrieve products by IDs.
// The price field belongs to the variants object because
// product variants can have different prices.
const GET_PRODUCTS_BY_ID = gql`
  query getProducts($ids: [ID!]!) {
    nodes(ids: $ids) {
      ... on Product {
        title
        handle
        descriptionHtml
        id
        images(first: 1) {
          edges {
            node {
              id
              originalSrc
              altText
            }
          }
        }
        variants(first: 1) {
          edges {
            node {
              price
              id
            }
          }
        }
      }
    }
  }
`;

export function ProductsPage({ productIds }) {
  const { loading, error, data, refetch } = useQuery(GET_PRODUCTS_BY_ID, {
    variables: { ids: productIds },
  });
  if (loading) return