#Handling API Requests on pages from Client / Server Side (SSR)

1 messages · Page 1 of 1 (latest)

half idol
#

New to Nuxt & SSR.

In Nuxt3, I have noticed that I cannot call useAsyncQuery on the client side. I get console warnings, and the docs say not to do this (but don't say why).

#

My pages/products/[product_slug].vue look like this:

<template>
  <product-view :product="product"/>
</template>

<script setup lang="ts">
import { useRoute } from 'vue-router'
import { isEmpty } from 'lodash'
import { useCatalogStore } from '@/pinia/CatalogStore'

const route = useRoute()
const product: any = useState()
const productSlug: ComputedRef<string> = computed(() => {
  return route.params.product_slug as string
})
const CatalogStore = useCatalogStore()

const setProductData = async(isServerSide: boolean = false) => {
  if (productSlug.value) {
    product.value = await CatalogStore.fetchProductBySlug({
      is_server_side: isServerSide,
      slug: productSlug.value
    })
  }
}

onMounted(async() => {
  if (isEmpty(product.value)) {
    await setProductData()
  }
})

onServerPrefetch(async() => {
  await setProductData(true)
})

watch(productSlug.value, async () => {
  await setProductData()
})

definePageMeta({
  key: route => 'view-product', // prevent newing up a component on each link click - reuse existing
})
</script>
#

You will notice that I am tracking if the request is originated from Server Side or Client side using an argument that is passed to setProductData().. my pinia CatalogStore.fetchProductBySlug action looks like this:

    async fetchProductBySlug(params: { is_server_side: boolean, slug: string, set_active?: true }): Promise<NuxtProduct> {
      const variables = {
        slug: `/products/${params.slug}/`,
      }

      let response: any
      if (params.is_server_side) {
        response = await useAsyncQuery({
          query: getProductBySlugQuery,
          variables: variables,
        })

      } else {
        response = await useApolloClient().client.query({
          query: getProductBySlugQuery,
          variables: variables,
        })
      }

      const data = params.is_server_side ? response.data.value : response.data
      const product = bigCommerceToNuxtProduct(data.site.route.node)
      this.addProduct(product)
      if (params.set_active) {
        this.setActiveProduct(product)
      }
      return product
    },

I check if params.is_server_side is true. If It is, I use useAsyncQuery, else useApolloClient(). This is wordy and doesn't seem right.. how should I be approaching this type of issue? I think I'm missing something fundamental..

runic rover
#

So I'm not sure on the specifics of the apollo client but could you provide some error logs because looking at the code for useAsyncQuery it looks like it shouldn't throw any errors as it's just a simple wrapper around Nuxt's useAsyncData

#

Also you don't have to pass the is_server_side variable through, you can just do

      if (import.meta.server) {
        response = await useAsyncQuery({
          query: getProductBySlugQuery,
          variables: variables,
        })

      } else {
        response = await useApolloClient().client.query({
          query: getProductBySlugQuery,
          variables: variables,
        })
      }
half idol
#

@runic rover - that saves some code, thank you. If I just useAsyncData on client side / server side, I see the following:

#

Everything seems to work fine, but I get that console warning..

runic rover
#

oh ok yeah so useAsyncData is supposed to be called during setup, the whole point of it is that it manages your async data and so calling it inside fetch means any data you put in it is immediately lost

#

so if you just need one time data to fill a pinia store I'd use $fetch

#

I'm sure there's something better for the apollo client but the documentation is lacking

half idol
#

So a pattern similar to the one i'm following to differentiate between SSR / client would be required for my use case..

#

basically a customer can view different products during a session on my website.. as they navigate around, I keep information in the store cached incase they navigate to a product they've already viewed, they've already got that info loaded

runic rover
#

Why don't you use just useAsyncData? I'm pretty sure that caches data between page navigations

#

ah ok I was wrong you have to add some extra things
https://www.youtube.com/watch?v=aQPR0xn-MMk

⚡️ Nuxt 3.8 was released just a day ago, packed with lots of amazing features. Among the updates, one change for useFetch and useAsyncData is pretty significant IMO - getCachedData. In this video, we will explore how that function can avoid superfluous calls to an API and cache data for visitors on the client, either until a hard-reload or...

▶ Play video
half idol
#

I've been messing with issues related to SSR / client side for a while now.. there was some issue wirth useAsyncQuery

#

Let me try it out again and recall what the warning was..

#

I've gone mad - sorry, so useAsyncQuery is what I'm currently trying to work with for SSR now

#

ex1. Sometimes the request to the product API can initiate on the server (the user visit a direct URL to a product page)

#

ex2. Other times, the request would originate from the client (the user clicks a related product on the product page they're currently on)

#

the way I understand it, in ex2, it would not be SSR?

runic rover
#
<template>
  <product-view :product="product"/>
</template>

<script setup lang="ts">
const route = useRoute()
const productSlug: ComputedRef<string> = computed(() => {
  return route.params.product_slug as string
})

const { data: product } = await useAsyncQuery({
  query: getProductBySlugQuery,
  variables: productSlug,
}) // Not sure on the specifics here

definePageMeta({
  key: route => 'view-product', // prevent newing up a component on each link click - reuse existing
})
</script>
runic rover
runic rover
#

This is pretty similar to what I would do in tanstack query so I'm hoping it's just as simple with this apollo stuff

half idol
#

I'm working with a lot of new to me technologies like GraphQL & SSR, so maybe its time to take a step back and read more about what Apollo does

#

I appreciate all of your help Sandvich.. I think I'm looking in the right direction now.. apollo is probably not what I want to use

runic rover
#

yeah imo graphql is bad and shouldn't be used for new projects, too many footguns

half idol
#

yea I prefer RESTful APIs, but I'm using BigCommerce headless for my store & getting info about a product is maybe 4 different API calls in REST or 1 API call in GraphQL

runic rover
#

If you're looking to manage state asynchronously and call api endpoints I'd recommend @tanstack/vue-query
But if you're learning learning and not just learning because you've taken over a project for work then I'd start with learning how to do things with just Nuxt works first, so you know fundamentals

runic rover
#

good luck!