The way to get this working is to use the CORS function from the remix-utils package.
If installing this on the Remix template of the shopify app, you will need to modify the remix.config.js file by including serverDependenciesToBundle: [ /^remix-utils.*/ ] in the module.exports as documented here. This is because remix-utils is published as ESM only and the remix.config.js file has the serverModuleFormat set to cjs. My editor still yells at me about the incorrect import method, but it works nonetheless. This is my updated remix.config.js file:
remix.config.js
if (
process.env.HOST &&
(!process.env.SHOPIFY_APP_URL ||
process.env.SHOPIFY_APP_URL === process.env.HOST)
) {
process.env.SHOPIFY_APP_URL = process.env.HOST;
delete process.env.HOST;
}
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
ignoredRouteFiles: ["**/.*"],
appDirectory: "app",
serverModuleFormat: "cjs",
future: {
v2_errorBoundary: true,
v2_headers: true,
v2_meta: true,
v2_normalizeFormMethod: true,
v2_routeConvention: true,
v2_dev: {
port: process.env.HMR_SERVER_PORT || 8002,
},
},
serverDependenciesToBundle: [
/^remix-utils.*/,
],
};
Then, import cors from the remix-utils package and update the return in your loader function of your API route with the cors function, as per their docs linked above. It should look like the following:
api.get-user.jsx
import { json } from '@remix-run/node';
import { cors } from 'remix-utils/cors';
export async function loader({ request }) {
const response = json({ body: 'data' });
return await cors(request, response);
}
I am now successfully making requests from the theme which is running locally.