Solved

App dev with remix template - Best way to process incoming data from the client?

Danh11
Shopify Partner
82 2 35

Apologies that this isn't exactly on the right board - there isn't any app dev spots to post it in.


I have used the Shopify CLI to create a Remix app. I need to receive customer usage data which will be processed and stored in the prisma DB. This is sent via the shopify app proxy.

 

If I setup a Remix route action to process the data, I receive the data ok but the response to the client is the page of that route. This doesn't seem like the right way to do it.

 

Am I better off running an Express server alongside the Remix app to process the incoming data and push it to the prisma db which the app can then reference? 

I'm new to Remix (and app dev in general), so sorry if there is an obvious answer to this.

Accepted Solution (1)

Danh11
Shopify Partner
82 2 35

This is an accepted solution.

I figured it out.

 

I was returning the component in the jsx file when I should have removed it when using this route as an API to process POST requests. It gets sent to the client as a response instead of the response from the action.

Bad:

import { json } from '@remix-run/node';

export async function action({ request }) {
  try {
    const data = await request.json();
    // process data
    const response = {};
    return json(response);
  } catch (error) {
    // handle error
  }
}

export default function incoming() {
}

 

 

 

Good:

import { json } from '@remix-run/node';

export async function action({ request }) {
  try {
    const data = await request.json();
    // process data
    const response = {};
    return json(response);
  } catch (error) {
    // handle error
  }
}

 

View solution in original post

Replies 16 (16)

Danh11
Shopify Partner
82 2 35

This is an accepted solution.

I figured it out.

 

I was returning the component in the jsx file when I should have removed it when using this route as an API to process POST requests. It gets sent to the client as a response instead of the response from the action.

Bad:

import { json } from '@remix-run/node';

export async function action({ request }) {
  try {
    const data = await request.json();
    // process data
    const response = {};
    return json(response);
  } catch (error) {
    // handle error
  }
}

export default function incoming() {
}

 

 

 

Good:

import { json } from '@remix-run/node';

export async function action({ request }) {
  try {
    const data = await request.json();
    // process data
    const response = {};
    return json(response);
  } catch (error) {
    // handle error
  }
}

 

Eniac
Shopify Partner
11 0 0

cool, i created a new remix route and removed the default export, now i can fetch my data in dev environment use the localhost url shopify provide to me. but what url should i use if i want to deploy it on online store?

Danh11
Shopify Partner
82 2 35

The URL you will be using in production to access the route will be the domain that you have set up for the app. So it could be 'https://myappurl.com/route/data' for example. This is if I understand you correctly.

For local development, I run a tunnel that points to the app. This way you don't have to keep changing the app URL each time you restart the app during development. I have setup a cloudflare tunnel and I launch it with their CLI.

 

You have to define a couple of things in the TOML files for this to work...


shopify.web.toml: You'll need to define the port for the app to use

 

name = "remix"
roles = ["frontend", "backend"]
webhooks_path = "/webhooks"
port = 8001

[commands]
dev = "npm exec remix dev"

[hmr_server]
http_paths = ["/ping"]

 

 

shopify.app.toml: Assign the tunnel URL to the application_url and the redirect_urls

 

# Learn more about configuring your app at https://shopify.dev/docs/apps/tools/cli/configuration

name = "postgres-starter"
client_id = "****"
application_url = "https://your-tunnel-url.com"
embedded = true

[access_scopes]
# Learn more at https://shopify.dev/docs/apps/tools/cli/configuration#access_scopes
scopes = "write_products"

[auth]
redirect_urls = [
  "https://your-tunnel-url.com/auth/callback",
  "https://your-tunnel-url.com/auth/shopify/callback",
  "https://your-tunnel-url.com/api/auth/callback"
]

[webhooks]
api_version = "2023-10"

[pos]
embedded = false

[build]
automatically_update_urls_on_dev = true
dev_store_url = "storename.myshopify.com"

 

 

I think you also need to update/check the URL in the app settings of the partner dashboard, and also within the app settings of the shopify admin (it's the Shopify App Proxy URL). I cant remember if these get updated automatically or not.

If you wanted to have the URL different in production and local development, you could use an ENV file where you set your development environment (dev/production). Your app would then set the appropriate URL depending on the environment. I usually use a ternary operator along the lines of:

 

const URL = process.env.ENVIRONMENT === 'dev' ? 'https://devurl.com' : 'https://produrl.com'

 

 

^^ This way, if you haven't defined the environment variable, it will fallback to  the production URL.

Having said that (the environment variable idea), it only works in a node environment - it won't work in a browser. To get around it in a browser, I use a ternary operator and check the contents of the URL (it may contain 127.0.0.1 if you're devloping a theme locally, for example).

Eniac
Shopify Partner
11 0 0
Thank you very much! Following your guidance, I was able to complete almost all the functionalities.
However, I would like to use the data stored in the app(remix) in my checkout extension(react). Is it possible to achieve this?
I can access it using the host provided by Cloudflare tunnel in the dev environment, or I can also access it using 'http://localhost:port'. For example, I have an API endpoint 'http://localhost:51319/app/my-app/get-info' that returns the correct data.
But when I publish and install it in my online store, what URL should I use to request the data from '/app/my-app/get-info'?
Do you have any knowledge about this?
Danh11
Shopify Partner
82 2 35

No worries. Glad I could be of some help!

In development, you should be able to access the data through the URL that points to your cloudflare tunnel. In production, this would be your app URL.

Is this not working for you?

Eniac
Shopify Partner
11 0 0
I seem to understand. When I used shopify cli this time, he recommended me to use remix mode. I mistakenly thought that my app service could be hosted on shopify.
 
but in fact, if I wanted to publish it to my online store, It seems I still need to deploy the remix service on the server of myown. Then I can have a route to use as the app url.
Danh11
Shopify Partner
82 2 35

Yep. I think it sounds like you're following correctly.

The remix template requires the app to be hosted externally, and that requires you to use the platform/server URL. Ideally you would register your own domain and set that up to point to your app.

AaronMarkle
Visitor
2 0 1

Hi @Danh11 , wondering if you could share some more of your code in regards to getting Prisma to work with a Hydrogen/Remix build? I am having trouble getting the Prisma client to work correctly. (Did you have to use Prisma Accelerate to get this working?)

 

Thanks,

Aaron

amarkle@lofta.com

Danh11
Shopify Partner
82 2 35

I haven't had to do that sorry, so I'm not really familiar with it. I've only been using the Shopify app remix template where Prisma is already setup. Depending on the app, and if you're wanting it to scale, I will swap out Prisma for another SQL storage solution as I have read that Prisma is not the best for production apps at scale. It's great for getting started quickly and has great syntax though! In my current app I have setup postgres and I'm using Supabase to host the database.

AaronMarkle
Visitor
2 0 1

Ah k, thanks for the reply. I will rethink if Prisma is needed for my use case.

michaelwanjek
Shopify Partner
1 0 0

Hello @Danh11,
I am developing a Shopify App with Supabase as well. I'm Using Heroku for hosting the app and Supabase Postgress as the Database.
It works great, but I see some latency when I interact with my app.

Do you have any recommendations for using external database providers like supabase?
Where do you host your app?

I first started with the sqlite/prisma configuration of the remix starter template, which felt "blazingly fast" as fireship would say. Then after deploying to heroku I felt like it's not the best way to use a sqlite database in production, especially when I want to distribute the app across several shopify shops, so I tried hosting the shopify app at vercel with a vercel postgress database which worked very well, but for any reason I couldn't get the for my app necessary shopify admin graphQL requests to work.

Long story short, I switched back to heroku deployment and everything works fine with the supabase postgress database, but it feels like it takes significantly more time on each database query than before with SQLite. Now I'm asking myself if there is maybe still some potential for optimizing the whole shopify-remix-app-with-supabase-stack.

I was also thinking about using the supabase RLS, but I don't hat time to look into the shopify session auth handling mechanism.
I think it would be awesome to use supabase postgress with rls in combination with the shopify session mechanism.


Greetings from Germany
Michael
michael@kreativkonnekt.de

Danh11
Shopify Partner
82 2 35

Lol @ the fireship quote!

 

I actually haven't deployed my app yet as I'm still working on it, so I can't shed any light on what latency I'm experiencing from the deployed app. Although I would assume it would be much the same compared to hitting the database when the app is running locally in dev seeing both would be making requests to an external server.

 

Come to think of it, I would probably expect a larger delay when querying a Supabase database, compared with SQLite/Prisma seeing one is being hosted on a remote server and the other is hosted on the same server as the app. That would be a benefit of using Prisma, but then you also have the downsides of using Prisma that people report.

 

I wonder why the graphQL requests weren't working with your app on vercel? Without knowing what was happening, I would think spending time to solve that issue might be well spent seeing they can host your database too. It would be nice to have the app hosted on the same platform that provides the database for low latency requests. I might try deploying to vercel when I'm ready and I will see what happens to my graphQL requests.

 

I also haven't yet enabled RLS on my Supabase database. It's on my list of things to investigate and implement as Supabase keeps yelling at me about it. It would definitely make it easy to stop one store being able to access another store's data.

noiseymur
Shopify Partner
20 2 8

Hey, @Danh11 , do you know how to set up Shopify Remix app with a separate express server or have a template for it by any chance ?

Danh11
Shopify Partner
82 2 35

No, sorry 🙂

CodeCodeCode
Shopify Partner
4 0 1

Hey Dan any ideas on why I would be getting a 404 error when trying to make an app proxy request from my theme app extension, here is the code 

<script>
document.addEventListener('submit'async function(event) {
if (event.target.matches('form[action="/cart/add"]')) {
console.log("Form submitted");
console.log("Form submitted");
const productId = "43565159415939";
const data = { productId };

 

const response = await fetch('/apps/proxy943/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
}
});
</script>
 
Here is my App proxy config
[app_proxy]
url = "https://rivers-sin-resistant-bigger.trycloudflare.com/app/ClientRequests"
subpath = "proxy943"
prefix = "apps"
 
 
this is my app.ClientRequests route, 
import shopify from "../shopify.server";
export async function action({requestparams}) {
const { admin } = await shopify.authenticate.public.appProxy(request);
const formData = await request.formData();
const productData = Object.fromEntries(formData);
const variantId = productData.productId;
const response = await admin.graphql(`
{
node(id"${variantId}") {
... on ProductVariant {
id
sku
title
price
product {
id
title
description
handle
featuredImage {
height
url
altText
}
}
}
}
}`);

 

const jsonResponse = await response.json();
return new Response(JSON.stringify(jsonResponse), {
status: 200,
headers: {
'Content-Type': 'application/json',
},
});
}
 
why would I get a 404 error?
Danh11
Shopify Partner
82 2 35

I'm wondering if you need to include the store URL in your fetch request. You currently '/apps/proxy943/', but you might you need something like 'https://storename.myshopify.com/apps/proxy493'?

 

I was using an app proxy at one point but removed it since I took another direction with what I needed to use it for, so that's kind of a guess seeing it's been a while since using an app proxy.

 

In production I think you would get the domain from the current URL, but I've never implemented this personally so I can't be sure.

 

Also check that the 404 isn't being caused by a CORS issue. The way you handle and return CORS preflight requests can be a little finicky in remix apps.