Skip to content

Instantly share code, notes, and snippets.

@ManUtopiK
Forked from productdevbook/urql.ts
Created March 9, 2023 00:45
Show Gist options
  • Save ManUtopiK/a25062b8ea5122c6d7d19b19ef394024 to your computer and use it in GitHub Desktop.
Save ManUtopiK/a25062b8ea5122c6d7d19b19ef394024 to your computer and use it in GitHub Desktop.
Nuxt 3 urql graphql
import { Client, createClient, dedupExchange, errorExchange, fetchExchange, ssrExchange } from '@urql/core'
import { ref } from 'vue'
import { devtoolsExchange } from '@urql/devtools'
import * as Session from 'supertokens-web-js/recipe/session'
import { authExchange } from '@urql/exchange-auth'
import { defineNuxtPlugin } from '#app'
const ssrKey = '__URQL_DATA__'
export default defineNuxtPlugin((nuxtApp) => {
const { vueApp } = nuxtApp
const env = useRuntimeConfig()
const ssr = ssrExchange({
isClient: process.client,
})
// when app is created in browser, restore SSR state from nuxt payload
if (process.client) {
nuxtApp.hook('app:created', () => {
ssr.restoreData(nuxtApp.payload[ssrKey])
})
}
// when app has rendered in server, send SSR state to client
if (process.server) {
nuxtApp.hook('app:rendered', () => {
if (nuxtApp.payload.data)
nuxtApp.payload[ssrKey] = ssr.extractData()
})
}
// Restore SSR payload once app is created on the client
if (process.client) {
nuxtApp.hook('app:created', () => {
if (nuxtApp.payload?.data)
ssr.restoreData(nuxtApp.payload.data[ssrKey])
})
}
const exchanges = [
dedupExchange,
ssr, // Add `ssr` in front of the `fetchExchange`
fetchExchange,
errorExchange({
onError(error) {
if (error.response?.status === 401)
window.location.href = '/logout'
},
}),
authExchange<{ token: string }>({
getAuth: async ({ authState }) => {
if (!authState) {
const token = await Session.getAccessToken() || ''
return { token }
}
return authState
},
addAuthToOperation: ({ authState, operation }) => {
const isMobile = env.public.mobile
if (!authState || !authState.token || !isMobile)
return operation
const fetchOptions
= typeof operation.context.fetchOptions === 'function'
? operation.context.fetchOptions()
: (operation.context.fetchOptions || {})
return {
...operation,
context: {
...operation.context,
fetchOptions: {
...fetchOptions,
headers: {
...fetchOptions.headers,
Authorization: `Bearer ${authState.token}`,
},
},
},
}
},
}),
]
const isDev = process.env.NODE_ENV === 'development'
// Devtools exchange
if (isDev)
exchanges.unshift(devtoolsExchange)
const client = createClient({
url: env.public.graphql,
exchanges,
fetchOptions: () => {
const env = useRuntimeConfig()
const isMobile = env.public.mobile
const lang = 'en'
const header = isMobile
? {
'X-language': lang || 'en',
'X-Client': isMobile ? 'mobile' : 'web',
} as HeadersInit
: {
'X-language': lang || 'en',
'X-Client': isMobile ? 'mobile' : 'web',
} as HeadersInit
return process.client
? {
headers: header as HeadersInit,
}
: {}
},
})
nuxtApp.provide('urql', client)
vueApp.provide('$urql', ref(client))
})
declare module '#app' {
interface NuxtApp {
$urql: Client
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment