I am developing ontop of the Remix app template. I have a route setup to return user data from the database.
I am making a request via the shopify app proxy to a route setup to fetch data from the app.
I understand the shopify app proxy won’t work while running the theme locally (I think?), so I have a domain pointing to a tunnel which points to the app running on localhost.
I can successfully make requests by hitting the endpoint via the tunnel in my browser.
Although the request is rejected when being made from the theme locally. I am returning headers to the preflight request, which I think are right, but it’s still not working.
I’m wondering if some middlewear when running the theme locally is interfering with something.
I am aware that I should be checking the digital signature from the request, and the preflight response headers probably aren’t the greatest, but I’m just trying to get this working first.
From your code, it seems like you’re handling the CORSflight request. However, you might want to add the “Access-Control-Allow-Credentials” header and set it to “true” if you’re using cookies for authentication. Also, consider allowing all headers in theAccess-Control-Allow-Headers" in your CORS configuration for testing purposes:
Moreover, ensure that your server is set up to handle OPTIONS requests. The preflight request is an OPTIONS request and server needs to respond with the appropriate CORS headers.
Unfortunately the request is still being blocked. There were a couple of typos which I think were a mistake? By Access-Control-Headers I assume you meant `
Access-Control-Allow-Headers`? Fixing them didn’t resolve the issue though.
As I’m using the Shopify app template, a lot of the server config is hidden and I can’t find a way to access or modify it. All that I can see is shopify.server.js. I’m not able to find any info on how to modify the express instance which I think is running.
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:
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.
Just to note - This actually still does not work when making the request via the Shopify app proxy while on local development. It does work ok when the theme is deployed and running from the Shopify server.
Although making requests to the app URL (with the tunnel running feeding traffic to the app running locally) does work in local development. So at least this makes it possible to develop locally. The app URL can be swapped out for the Shopify app proxy when it comes to deployment. This won’t be a great dev experience if/when the app proxy signature is checked on the endpoint provided by the app, but that’s a problem for another time.
As you can see I’ve give the public path with url where our app will be hosting I’ve named it SHOPIFY_APP_URL but it’ll be heroku url where our app is hosted.
We’ve to do it as when we use as proxy with default publivPath it try to access build files using shopify domain and there is error not found.
We’ve add that route as app proxy so we can access through the store.
Then we’ve hosted our app on the heroku and added that url like this heroku_url/app_route in app proxy.
Now we’re geting files but getting cors error while running that url as app aproxy.
css file is able to load but the build js files are giving cors errors.
I dont able to get where i will add cors headers so my store can access the shopify app build files hosted on heroku can remove cors errors
I’m not really familiar with what you’re trying to do there, sorry!
If you’re trying to define a new route, that would be done with a jsx or tsx file named appropriately. For example, api.endpoint.jsx for the path of /api/endpoint. You can then use the cors package that I mentioned in my previous comment to add the headers to the response.
Unless I have misinterpreted what you’re trying to achieve?
Thanks, i’ve been trying to make a fetch request from my extension to my server. Even tried what worked for you. My loader function is similar to yours. Any idea what I’m doing wrong?
Hey! I need a little more information What error are you getting? What does the function look like where you’re making this request? What does your route look like? Is the route being hit by the request? Is it failing to return anything at all?
It seems like the error is occuring during the preflight request that the client is making. The server isn’t handling the OPTIONS request type, which is what the preflight is, so it’s causing the error and in turn the client also fails on the preflight request.
It’s a bit hard for me to tell you exactly how to fix it, but look into what a preflight request is and how to handle it. Maybe ChatGPT could point you in the right direction as well.
import { json } from "@remix-run/node";
import { authenticate } from "../shopify.server";
import { getMyAppModelData } from "~/db/model.server";
export const loader = async ({ request }) => {
// Get the session for the shop that initiated the request to the app proxy.
const { session } = await authenticate.public.appProxy(request);
// Use the session data to make to queries to your database or additional requests.
return json(await getMyAppModelData({shop: session.shop));
};
Ok if you are new to this I wasted a day to fix this error
this error comes when you do POST/GET request to your remix API from your DEV store via embeds
Reason is you are not managing your OPTIONS REQUEST correctly
NOTE: you never gets this error when you using this “Cloudflare tunnel Urls” You gets these Cors errors when you host you host your Remix somewhere like a VPS
and with remix this is how you should you mange it
remix-utils is the main package here
check it’s doc for how to restrict your site more.
import { json } from "@remix-run/node";
import { cors } from "remix-utils/cors";
import type { LoaderFunctionArgs, ActionFunctionArgs } from "@remix-run/node";
export async function loader({ request }: LoaderFunctionArgs) {
const url = new URL(request.url);
const shop = url.searchParams.get("shop");
// This is where you need to cors safe your request
if (request.method === "OPTIONS") {
const response = json({
status: 200,
});
return await cors(request, response);
}
if (!shop) {
return json({
message: "Missing data. Required data: shop",
method: "GET",
});
}
const response = json({
ok: true,
message: "Success",
data: "analyticDbResponse",
});
return cors(request, response);
}
const addAnalytic = async (data) => {
return "some db stuff"
};
export async function action({ request }: ActionFunctionArgs) {
// for double check I added this here too
if (request.method === "OPTIONS") {
const response = json({
status: 200,
});
return await cors(request, response);
}
if (request.method == "POST") {
let data = await request.json();
try {
if (data.shop !== undefined) {
addAnalytic(data); // me doing some db updates
const response = json({
message: "success",
});
await cors(request, response);
return response;
} else {
return json({
message: "Missing data. Required data: shop",
method: "POST",
});
}
} catch (error) {
console.log("error", error);
return json(
{
message: "error with endpoint",
method: "POST",
},
400,
);
}
}
}
Does anyone know how to implement this solution with the current version of the Shopify Remix app template now with Vite? There isn’t a remix.config.js file anymore.
This worked for me as well. I also wasted a couple days on this even after finding this post. I didn’t realize the OPTIONS method is handled by the loader function.