gnikyt Code ramblings.

Shopify Checkout Extension to backend fetching

There are several posts around about people having issues figuring out how to send a fetch request from their checkout extension to their app backend (Remix). Shopify’s documentation around this is rather limited as well. So, I have put together a small example of how you can achieve this!

Assuming your extension was generated by the Shopify CLI, you should have a strucutre as such:

  extensions/
    [your-ext]/
      Checkout.tsx
      package.json
      tsconfig.json
      shopify.extension.toml
      README.md

Create a new file in your extension directory called useSessionFetch.ts and paste the following contents:

// extensions/[your-ext]/useSessionFetch.ts

import type { SessionToken } from "@shopify/ui-extensions/checkout";

/**
 * Fetch using session token.
 *
 * @param sessionToken - Session token service.
 */
export default function useSessionFetch(sessionToken: SessionToken) {
  /*
   * Fetch resource.
   *
   * @param url - URL or request object for fetch.
   * @param init - Configuration for fetch.
   */
  return async function (url: string | URL | Request, init?: RequestInit) {
    const token = await sessionToken.get();
    return fetch(url, {
      ...(init || {}),
      headers: {
        ...(init && init.headers ? init.headers : {}),
        Authorization: `Bearer ${token}`,
      },
    });
  };
}

This function will accept the session token service and return a function you can use instead of fetch. Upon calling it, the code will automatically get a session token to append to the fetch request’s headers. Its really just a small but helpful hook to wrap around fetch.

To utilize this in your extension, example:

// extensions/[your-ext]/Checkout.tsx

import { useSessionToken } from "@shopify/ui-extensions-react/checkout";
import useSessionFetch from "./useSessionFetch";

function Extension() {
  const sessionToken = useSessionToken();
  const sessionFetch = useSessionFetch(sessionToken);

  useEffect(() => {
    (async () => {
      // Use `sessionFetch` instead of `fetch`
      const response = await sessionFetch("/some/path/to/remix/backend");
      if (response.ok) {
        const { data } = await response.json();
        setData(data);
      }}
    })();
  }, []);

  // ...
}

On your backend:

// routes/some.path.to.remix.backend

import { authenticate } from "../shopify.server";
import { json, type LoaderFunctionArgs } from "@remix-run/node";

export async function loader({ request, params }: LoaderFunctionArgs) {
  const { sessionToken, cors } = await authenticate.public.checkout(request);
  const shop = ShopDomain(sessionToken.dest);

  // ...

  return cors(json({
    data: { hello: "world" },
  }));
}

Now, with this hook, the token, and utilization of authenticate.public.checkout, you can easily make a fetch request from your extension to your backend.