How to create a GraphQL client in Remix getting the POST request from a store frontend?

How to create a GraphQL client in Remix getting the POST request from a store frontend?

angpro
Shopify Partner
10 1 1

I am developing a shopify app with the Remix template. My app provides a theme app extension for shopify stores.

 

The logic is following: the theme app extension adds a submit form on the shop frontend; a user submit some details on this form. Then the backend of the app gets the POST request, then create a GraphQL client that makes a query to DB based on submitted details.

 

My question is following: how should I create a GraphQL client getting the POST request from a store frontend?

 

I found shopify.authenticate and shopify.unauthenticated

 

If I understand it correctly, I should use shopify.authenticate getting the POST request from a store frontend (because it's said that I cannot use shopify.unauthenticated  if the request coming from Shopify). 

So, I am using shopify.authenticate.public to get the session token to use it after for the GraphQL client.

 

But I am getting an error trying to get the session token. What I am doing wrong?

 

 

Here is the code:

-------

import { GraphQLClient, gql } from 'graphql-request';
 
importLATEST_API_VERSION } from "@shopify/shopify-app-remix/server";
 
import { unauthenticated, authenticate } from "../shopify.server";
 
 
 
async function shopifyGraphQLRequest(shopDomain, accessToken, graphqlQuery) {
      const endpoint = `https://${shopDomain}/admin/api/${ LATEST_API_VERSION }/graphql.json`;
      const client = new GraphQLClient(endpoint, {
      headers: {
            'X-Shopify-Access-Token': accessToken,
             },
      });

const data = await client.request(gql`${graphqlQuery}`);
return data;
}

 

// Here I am handling the POST request from a shop frontend

export async function action({ request }) {
       .....
       const { sessionToken } = await authenticate.public.checkout(request);
       const data = await shopifyGraphQLRequest(shopDomain, sessionToken, QUERY);
       ...
       }
-----

 

Replies 3 (3)

Danh11
Shopify Partner
84 2 38

I think you're probably facing this issue outlined here. I've just lost many hours to it. I hate to come across negative but it's hard to stay cool when we are dealing with issues like this 🙂

 

edit: Having thought about this more - surely it is not actually a problem and we're doing something wrong. The app would not work if the token wasn't working. I just can't work out what is wrong.

Danh11
Shopify Partner
84 2 38

I have managed to work around the issue. I'm sure it's not really best practice but it works.

 

I found the accessToken being stored in the shopify_sessions table of the database. I'm using postgres, but you'd be able to find it in whatever storage you're using.

 

So I'm making a request to the database to fetch the access token, I'm extracting the shop by accessing sessionToken.input_data.shop.domain, and then making the graphql request.

 

Here's how I've implemented it with some helper functions..

 

Remix action

 

export const action = async ({ request }) => {
  const { cors, sessionToken } = await authenticate.public.checkout(request);
  
  const shop = sessionToken.input_data.shop.domain;

  // call to storage for access token
  const accessToken = await fetchAccessToken(shop)

  const productId = '123456789';

  const product = await getProduct({ shop, accessToken, productId });

  console.log(product)

  // rest of code...
};

 

 

getProduct()

 

export default async function getProduct({ shop, accessToken, productId }) {
  const variables = {
    id: `gid://shopify/Product/${productId}`
  }

  const response = await graphQLRequest({
    shop,
    accessToken,
    query: GET_PRODUCT,
    variables
  });

  return response;
}

 


graphQLRequest()

 

export default async function graphQLRequest({ shop, accessToken, query, variables }) {
  try {
    const url = `https://${shop}/admin/api/${ LATEST_API_VERSION }/graphql.json`;

    const requestHeaders = {
      'X-Shopify-Access-Token': accessToken,
    }

    const data = await request({
      url,
      document: query,
      variables,
      requestHeaders
    })

    return data;
  } catch (error) {
    console.log('error', error)
  }
}

 

 

I'm using request() from the graphql-request client instead of GraphQLClient so that I can pass in variables (wasn't sure how to do this with GraphQLClient).

 

I'd love to hear if there's another way we're meant to be doing this that works.

 

 

angpro
Shopify Partner
10 1 1

That is very helpful. 

I also have found another way auth the request and call Admin API using authenticate.public.appProxy (when the request coming through Proxy link from the shop frontend):

 

export async function action({ request }) {
    ....
    const response = await authenticate.public.appProxy(request);
    const responceGraphQL = await response.admin?.graphql(QUERY);
    ....
    }

 



But I also faced the problem that the Proxy Link does not work without selected distributed method: either Custom Distribution (the app available with the link) or Public Distribution (available on the Store). And it was not clear in Docs.