• nuxt
  • graphql
  • jamstack

Static website and GraphQL queries with Nuxt.js

Graphql client is king.

Published on : August 5, 2021

The problem

I encountered a nasty bug while using static generation with Nuxt and nuxt apollo client. I found the issue already reported on github.

It seems the module doesn't handle static generation correctly with nuxt generate.

I could find request to my local API url after the static generation. Moreover, it also seemed like <nuxt-link> navigation was broken.

The solution 🙌

Fortunately, there is another Nuxt module that handles GraphQL requests!

[Nuxt graphql request to the rescue!](https://github.com/gomah/nuxt-graphql-request 'Working module github repository's (new tab)')

The conf

nuxt.config.js
buildModules: [
  'nuxt-graphql-request',
],
graphql: {
  clients: {
    default: {
      endpoint: 'http://API_URL/graphql',
      options: {
        headers: {
          authorization: 'Bearer API_TOKEN',
        },
      },
    },
  },
},

The request

The best approach so far is to use asyncData in pages and fetch in components. Using fetch in pages does not work well at all with nuxt generate.

I also install the graphql-tag package (only in devDependencies) to be able to import directly .gql files.

Query example:

homepage.gql
query {
  homepage {
    title
    subtitle
    hero {
      id
      alt
    }
  }
}

Inside a page

index.vue
<script>
import homepageQuery from '~/graphql/queries/singles/homepage'

export default {
  async asyncData({ $graphql }) {
    const data = await $graphql.default.request(homepageQuery)
    return { data }
  },
}
</script>

Inside a component

It is safer to wait until fetch has received a response before displaying anything. You can use $fetchState to be sure (documentation).

Header.vue
<template>
  <header v-if="!$fetchState.pending"></header>
</template>

<script>
import headerQuery from '~/graphql/queries/singles/header'

export default {
  data() {
    return {
      data: {},
    }
  },
  async fetch() {
    try {
      const data = await this.$graphql.default.request(headerQuery)
      this.data = data
    } catch (error) {
      console.error(JSON.stringify(error, undefined, 2))
    }
  },
}
</script>

Options

To pass options to the request, for example for a multilingual version with nuxt/i18n and/or a url parameter in a dynamic page:

_slug.vue
<script>
import articleQuery from '~/graphql/queries/articles'

export default {
  async asyncData({ $graphql, app, params }) {
    const locale = app.i18n.localeProperties.iso
    const data = await $graphql.default.request(articleQuery, {
      code: locale,
      slug: params.slug,
    })
    return { data }
  },
}
</script>