Solved

Storefront API undefined with AppProxy

TheodorFreundHT
Shopify Partner
7 0 0

Hello everyone,

 

I have an odd behaviour that I cannot quite understand:
I created an extension that allows a customer to interact with our business backend through the store's frontend. I achieved this through a route that first makes a request to our business backend and follows that up with requests to the storefront api.
When running it locally it works just fine, but when I deploy it to our dev store, I get the following error:

 

 

 

TypeError: Cannot read properties of undefined (reading 'graphql')
    at getImageByVariant (/app/build/index.js:583:40)
    at action5 (/app/build/index.js:575:28)
    at Object.callRouteActionRR (/app/node_modules/@remix-run/server-runtime/dist/data.js:35:16)
    at callLoaderOrAction (/app/node_modules/@remix-run/router/router.ts:4020:16)
    at submit (/app/node_modules/@remix-run/router/router.ts:3133:16)
    at queryImpl (/app/node_modules/@remix-run/router/router.ts:3068:22)
    at Object.queryRoute (/app/node_modules/@remix-run/router/router.ts:3018:18)
    at handleResourceRequestRR (/app/node_modules/@remix-run/server-runtime/dist/server.js:296:20)
    at requestHandler (/app/node_modules/@remix-run/server-runtime/dist/server.js:104:18)

 

 

 

 The Dockercontainer is running in the cloud, I set the correct values for the environment variables for scope, shopify_key, shopify_secret and app_url and the app deploys as normal. In the partner dashboard I checked the urls => all conforming to the container's address including the app proxy.


I installed it on the target shop, added the app-block to a page and opened it in preview. That is when the error occurred. 

 

This is the enpoint in question:

import { json } from "@remix-run/node";
import { authenticate } from "../shopify.server";
const HTV_API_BASE_URL = process.env.HTV_API_BASE_URL


export const action = async ({ request }) => {

var request_params = await request.json()
var token = request_params.token

let data = await fetch(HTV_API_BASE_URL + '/customers/v1/access', {
method: 'GET',
headers: {
'Content-Type': 'multipart/form-data;',
'X-Htv-User-Token' : token
}
}).then(response => {

return response.json();
}).catch(error => {
console.log(error)
return {
"status" : "error"
}
});
// if we received correct data, enhance dataset with shopify data
if (!!data && data.status == "OK") {
let main_product = data.token_data.data.proposed_changes
console.log(main_product)
console.log(main_product.alternative)
console.log(main_product.alternative.molecule_group)
main_product.imageUrl = await getImageByVariant(request, main_product.shop_identifier)
main_product.molecule_group = main_product.alternative.molecule_group

let alternative = main_product.alternative
alternative.imageUrl = await getImageByVariant(request, alternative.shop_identifier)
}
return data;
}

async function getImageByVariant(request, variant_id) {
// gets the image url from shopify
const { storefront } = await authenticate.public.appProxy(request);
try {
var shopify_variant_id = "gid:\/\/shopify\/ProductVariant\/" + variant_id
const response = await storefront.graphql(
`#graphql
query($id: ID!) {
node(id: $id) {
... on ProductVariant {
id
product {
featuredImage {
url
}
}
}
}
}`,
{
variables: {
"id" : shopify_variant_id
},
},
);
// const responseJson = await response.json();

let data = await response.json();
return json({
"image_url" : data.data.node?.product?.featuredImage?.url
});
}
catch (error) {
console.log(error)
return json({
"image_url" : null
});
}
};


 

I found a lot of very similar problems, all pertaining to { admin } = authenticate.public.appProxy, but none to storefront. I presume this is due to some problem with access rights, but this is the scopes and app proxy definition from the toml:

[app_proxy]
url = REDACTED FOR SAFETY
subpath = "oos"
prefix = "apps"

[access_scopes]
scopes = "read_products,unauthenticated_read_product_listings"


Can someone spot the mistake?

Accepted Solution (1)
ninosition
Shopify Partner
2 1 0

This is an accepted solution.

Not sure if it would be the same type of solution, but the Remix app uses a sqlite file. This apparently gets deleted on the Dockerfile when going into production. By removing the line which removes the dev.sqlite file, I was able to get my api calls to Storefront API working. 

There are Sessions in this database, and they do get asked for by the basic Remix code. 

View solution in original post

Replies 3 (3)

ninosition
Shopify Partner
2 1 0

Managed to find a solution to this? Running into the exact same problem. 

TheodorFreundHT
Shopify Partner
7 0 0

@ninosition No.
As you can see from my code, I made a call to my own backend first.
I know just make the API calls from there through the Admin api in python.
This works just fine and without any issues for now, but it makes my toes curl, because it is un-clean.
I tried it with unauthenticated instead of authenticated as well, but no avail
I also debugged the request in detail and both the shop identifier and the signature value are sent as query parameters in the request, so I just gave up and used the method I know works but it is very ugly imho...

ninosition
Shopify Partner
2 1 0

This is an accepted solution.

Not sure if it would be the same type of solution, but the Remix app uses a sqlite file. This apparently gets deleted on the Dockerfile when going into production. By removing the line which removes the dev.sqlite file, I was able to get my api calls to Storefront API working. 

There are Sessions in this database, and they do get asked for by the basic Remix code.