URQL & Next RSC Data Fetching w/ Auth Tokens?
Unanswered
Kawakawa posted this in #help-forum
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.
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
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'))
...
}@Rafael Almeida you need to create a new client for each request, you receive the token through a param and return the client:
js
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'))
...
}
KawakawaOP
See I was actually thinking about doing it like this, but would this not create a memory leak/have memory issues/any issues at all?
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
An example of one of my custom made functions from one of those files:
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 itselfor you could accept the client as an argument if you prefer to create it in the component itself
@Rafael Almeida 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
KawakawaOP
Hmm ok. This seems like a good solution I could work with, but then wouldn't creating the client in that file then have the memory issues?
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?
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 componentsthis 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