Diizzayy / nuxt-graphql-client

⚡️ Minimal GraphQL Client + Code Generation for Nuxt3
https://nuxt-graphql-client.web.app
MIT License
355 stars 44 forks source link

[Bug] Shopify GraphQL returns 403 after client side navigation #80

Open Baroshem opened 2 years ago

Baroshem commented 2 years ago

Hi @Diizzayy !

I encountered a strange issue when working with your module (which is great BTW)

Everything works great when accessing the page from URL, but when I am doing a page transition (i.e. from Homepage to Product Page) I am getting a 403 on graphql.json. I am using the example with Shopify.

Have you encountered something like this already?

Diizzayy commented 2 years ago

Does your Shopify api require authentication?

I'm not certain but I suspect this may be an authentication issue, when interacting with a GraphQL API that requires authentication, by default tokens passed via config are only applied on server side to prevent the token being leaked client side.

Baroshem commented 2 years ago

Looking at this issue, I suppose it does (like it cannot fetch the graphql json from shopify on the frontend due to lack of the token).

useAsyncData probably tries to fetch the same data on the frontend but fails due to not having the auth correctly served. I will take a look at it and let you know :)

Diizzayy commented 2 years ago

@Baroshem I'm interested to hear your findings. If our suspicions are correct you can have a look at retaining config level tokens to aid in debugging this issue

Baroshem commented 2 years ago

Hey, it seems like I have to retain the token for client side data fetching. Do you know any approach that I could do to somehow force client side fetch through some kind of server middleware to not retain the token?

Basically what is happening that on client side navigation, the request to graphql.json is being triggered but because the token is applied only on the server side, this navigigation is failing with 403

Baroshem commented 2 years ago

For now I will leave it as it is as I cannot find any workaround.

BTW, do you have any example of triggering mutation on the client side? Like adding product to cart by clicking a button on the product page?

In the docs I was only able to see examples of useAsyncData with queries

Diizzayy commented 2 years ago

@Baroshem

In the docs I was only able to see examples of useAsyncData with queries

I need to update the documentation with clearer examples for different use cases.

BTW, do you have any example of triggering mutation on the client side?

This can be achieved as explained below.

Nuxt-app/queries/user.gql

mutation addUser($input: UserInput!) {
    addUser(input: $input) {
      uid
      role
      name
      email
      picture
    }
}

query getUsers {
    users {
        uid
        role
        name
        email
        picture
    }
}
<script lang="ts" setup>
// Everything here ( gql functions, their inputs and return types ) should be fully typed

async function addUser() {
  const { addUser } = await GqlAddUser({
    input: {
      name: 'John Doe',
      email: 'jd@example.com'
    }
  })

  // additonal logic
}

async function getUsers() {
  const { users } = await GqlGetUsers()

  return users
}
</script>

ps: the properties returned by gql functions are named based on the GraphQL operation name

Diizzayy commented 2 years ago

For now I will leave it as it is as I cannot find any workaround.

@Baroshem I'll look into a way to circumvent this case for instances where the GraphQL query should only be made in a secured environment (server side) to prevent private token usage.

As this use case isn't limited to this module, it would be good if we provide a first class workaround using the capabilities that Nuxt 3 offers

Baroshem commented 2 years ago

That would be awesome @Diizzayy !

Thank you for the example and the explanation. In the upcoming days I will be releasing a video tutorial about Building Headless Commerce with Nuxt 3, Shopify and Tailwind, and I decided to use your module as it provides the best Developer Experience :)

Basically:

<script setup lang="ts">
const { data } = await useAsyncData('products', () => GqlProducts({ first: 3 }))
</script>

<template>
  <div>
    <HeroBanner />
    <ProductList :products="data.products.edges"/>
  </div>
</template>

I will let you know when the video will be released! :)

Diizzayy commented 2 years ago

@Baroshem I love that you're delving into creating video tutorial, those will definitely be a great help to many newcomers in the Nuxt community.

I'm looking forward to checking out the video when it's released 😁

it provides the best Developer Experience :)

I'm glad to hear that you're liking it, it's going to get even better from here.

iBobik commented 1 year ago

Btw, I have this issue on a local dev server, productions is statically generated and seems working well if I query data only in setup.

Diizzayy commented 1 year ago

@iBobik Have you attempted enabling the retainToken flag?

iBobik commented 1 year ago

@Diizzayy I does not want to expose this token to the frontend, I want to enforce SSR for this calls.