Next.js Discord

Discord Forum

URQL & Next RSC Data Fetching w/ Auth Tokens?

Unanswered
Kawakawa posted this in #help-forum
Open in Discord
KawakawaOP
Hi there! I have a HTTP (GQL) API Client set up in a folder in my SRC directory. I need to put the user's token inside of this file, as the auth header. How would I be able to set this header in the one file if everyone has a different token? Might be over-thinking this.

import { Client, cacheExchange, fetchExchange } from "@urql/core";
import { env } from "@/env.mjs";

export const gqlClient = new Client({
  url: env.NEXT_PUBLIC_API_URL ?? "redactedapiurlhere", // ? Default API URL Value
  exchanges: [cacheExchange, fetchExchange],
  fetchOptions: {
    headers: {
      "X-Authorization-Realm": "dashboard",
      "authorization": <TOKEN HERE>??
    },
  },
});


Also, adding the token in the fetch options on a per-request basis would be a bit of a pain as I have a lot of queries, I'm not going to lie - so if I cannot do something with the client.ts file for the URQL client, is there another way to do it that's cleaner?

15 Replies

you need to create a new client for each request, you receive the token through a param and return the client:
import { cache } from 'react'

export const getGqlClient = cache((token) => {
  return new Client({ ..., headers: { "Authorization": token } })
}

// in your page
import { cookies } from 'next/headers'
import { getGqlClient } from '...'

export async function Page() {
  const client = getGqlClient(cookies().get('token'))
  ...
}
no, the cache from React only lives throughout the duration of the request
@Rafael Almeida no, the `cache` from React only lives throughout the duration of the request
KawakawaOP
Ah, ok. Say then I had all my requests in TS files in src > utils - what would be the best way to do this?

An example of one of my custom made functions from one of those files:
import { graphql } from "@/graphql";
import { gqlClient } from "@/graphql/client";
import { type GetLogs } from "@/graphql/graphql";

export const loggingCategoriesQuery = graphql(`
  query GetLoggingCategories($serverId: UUID!) {
    server(id: $serverId) {
      loggingCategories
    }
  }
`);

export async function getLoggingCategories(serverId: string) {
  const res = await gqlClient
    .query(loggingCategoriesQuery, { serverId }, { requestPolicy: "network-only" })
    .toPromise();

  return res.data;
}
I am not sure there is a best way to solve this, there are multiple solutions and you will need to figure out whichever works better for you. the simplest solution would be to pass the token as a argument for getLoggingCategories so it can create the client itself
or you could accept the client as an argument if you prefer to create it in the component itself
Or can I use the cache thingy in there as well 🤔
these functions should still use the same exported function wrapped by cache, so they will all get the same instance
@Rafael Almeida these functions should still use the same exported function wrapped by `cache`, so they will all get the same instance
KawakawaOP
But can I call that cache function inside of that file? Or does it have to be in a file which contains a component?
Never seen this method before, gonna be honest - so sorry if I am pestering you! 😁
I am pretty sure you can call the function in any file, as long as this file is eventually imported by a server component
@Rafael Almeida I am pretty sure you can call the function in any file, as long as this file is eventually imported by a server component
KawakawaOP
Yeah, alright.

Am I also right in saying that this way of doing it is a tad janky? If so, what would be a better way do you think to do it, or do you personally know of any better GQL packages etc, maybe even for Next specifically?
imo it is easier now, in the past you still had to create a new instance for every request, but you could only do it in getServerSideProps so you had to fetch everything there and pass to the underlying components
this client situation is the same even for REST requests, you can't use the same client for every user if the client has a cache otherwise you can leak data from one user to the other