Closed peterkuykendall closed 6 months ago
ah -- just saw this: https://github.com/apollographql/apollo-client-nextjs/issues/103
registerApolloClient is a singleton
Yes, but per request. Your registerApolloClient
makeClient
function will be executed once per request, so you can also just call something like cookies
in there - you just never ever ever should access the cookies outside of makeClient
and pass them in via scope or parameters, since then they'll be shared across all requests.
Great, thanks for explaining. I'd appreciate some help here then.
To be totally clear: If you're saying that I shouldn't pass in the cookie outside of makeClient, am I correct in reading that I should also not be setting the cookie with the new: client.defaultContext.token = newToken;
in the calling page because there's a possibility that between the setting and the makeClient, it could be set or over-written by another unrelated request?
If that's the case, then I'm also not clear how to get the jwt from inside of makeClient because I don't see how I can have access to any page, context or cookies there.
No, you misread me:
every Request has it's unique ApolloClient instance. Inside of your React component tree (in Client Components), calling any Apollo hooks and every time you call getClient
(in RSC), you will always get the right instance for this request.
You can modify that instance however you like.
The following pattern is dangerous:
const token = cookies().something;
const { getClient } = registerApolloClient(() => {
/** do not ever reference the global "token" here! */
});
Instead, do this:
const { getClient } = registerApolloClient(() => {
const token = cookies().something;
});
doing this is likely pointless: getClient().defaultContext.token = newToken;
- because where would you get a new token when your ApolloClient
only exists for the time of a single render?
wonderful. Thanks for clarifying how it should be organized. I'm in good shape now.
@phryneas
Wondering if this looks fine to you (seems like it works for me), specifically for RSC. Thanks in advance!
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { registerApolloClient } from '@apollo/experimental-nextjs-app-support/rsc';
import { fetchAuthSession } from 'aws-amplify/auth/server';
import { cookies } from 'next/headers';
import { env } from '~/_env';
import { runWithAmplifyServerContext } from '~/authentication/utils/serverSideAuth';
const authTokenLink = setContext(async () => {
// Could be any async way of fetching the token, but this is with Amplify
const session = await runWithAmplifyServerContext({
nextServerContext: { cookies },
operation: (contextSpec) => fetchAuthSession(contextSpec),
});
if (session.tokens?.idToken) {
return {
headers: {
Authorization: session.tokens?.idToken?.toString(),
},
};
}
return {
headers: {
'X-Api-Key': env.NEXT_PUBLIC_AWS_APPSYNC_API_KEY,
},
};
});
export const { getClient } = registerApolloClient(() => {
return new ApolloClient({
cache: new InMemoryCache(),
link: authTokenLink.concat(
new HttpLink({
uri: env.NEXT_PUBLIC_AWS_APPSYNC_GRAPHQL_ENDPOINT,
}),
),
});
});
@shawngustaw that looks good to me, but I have to admit that I am not familiar with your specific way of fetching the token. Glad to hear it works 😊
I'm only interested in the next js app folder approach at this point.
With Clerk for next.js app, I can get a token from a page, but I can't see how to get it from the environment like you do with the Next Auth approach https://github.com/apollographql/apollo-client-nextjs/issues/44
So I'd think I'd need to pass the token in with the getClient/registerApolloClient call in the examples, export const { getClient } = registerApolloClient(() => {
but I don't see how to do that because the registerApolloClient doesn't take args.
Could you share how to get the client for an Clerk token?
I'm also curious -- where you've said in other posts that registerApolloClient is a singleton, is that also the case on the server only app folder approach? And if so, how does that work in a multi-user situation where each user has different creds?