-
Notifications
You must be signed in to change notification settings - Fork 191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to configure apollo clients using Nuxt 3 runtime config? #442
Comments
Solved it by using apollo "links". They work like a middleware and allow you to modify any client attribute before making the request. |
#463 You can try my solution to rewrite the apollo link |
Based on @nguyenshort comments, by defining the ApolloLinks, including the HttpLink, in the project's plugin configuration, you can overwrite the default links by injecting the environment variable with the NuxtJS runtimeConfig.
import { createHttpLink, from } from '@apollo/client/core';
import { onError } from '@apollo/client/link/error';
import { setContext } from '@apollo/client/link/context';
export default defineNuxtPlugin((nuxtApp) => {
// Get Nuxt runtimeConfig and apollo instance
const runtimeConfig = useRuntimeConfig();
const { $apollo } = useNuxtApp();
// Create custom links (auth, error, http...)
// Create an authLink and set authentication token if necessary
const authLink = setContext(async (_, { headers }) => {
return {
headers: {
...headers,
Authorization: `Bearer ${[...]}`,
},
};
});
const httpLink = authLink.concat(
createHttpLink({
uri: runtimeConfig.public.apiGraphqlUrl,
})
);
const errorLink = onError((err) => {
nuxtApp.callHook('apollo:error', err);
});
// Set custom links in the apollo client (in this case, the default apollo client)
$apollo.defaultClient.setLink(from([errorLink, httpLink]));
nuxtApp.hook('apollo:error', (error) => {
console.error(error);
});
}); This snippet overwrites the ApolloLinks that are created here within the apollo library. const authLink = setContext(async (_, { headers }) => {
...
$apollo.defaultClient.setLink(from([errorLink, httpLink])); |
Based on @juanmanuelcarrera and @manakuro comments, I am using the following setup in Nuxt 3. Used dependencies: "devDependencies": {
"@nuxtjs/apollo": "5.0.0-alpha.5",
"nuxt": "3.1.1",
"@types/node": "18.11.17",
"graphql": "16.6.0",
"typescript": "4.9.3"
}, File export default defineNuxtConfig({
modules: [
'@nuxtjs/apollo',
],
runtimeConfig: {
public: {
// override with `.env` var `NUXT_PUBLIC_APOLLO_ENDPOINT` (oc do not use `process.env.*`)
APOLLO_ENDPOINT: '',
},
},
// for `@nuxtjs/apollo`
apollo: {
clients: {
default: {
httpEndpoint: '', // must be present but will be overridden in the external config TS file (see above)
},
},
},
}) File import { createHttpLink, from, ApolloLink } from '@apollo/client/core'
import { onError } from '@apollo/client/link/error'
import { setContext } from '@apollo/client/link/context'
import { provideApolloClient } from '@vue/apollo-composable'
/**
* See example: https://github.com/nuxt-modules/apollo/issues/442
*/
export default defineNuxtPlugin((nuxtApp) => {
const envVars = useRuntimeConfig()
const { $apollo } = nuxtApp
// trigger the error hook on an error
const errorLink = onError((err) => {
nuxtApp.callHook('apollo:error', err) // must be called bc `@nuxtjs/apollo` will not do it anymore
})
// create an authLink and set authentication token if necessary
// (Can not use nuxt apollo hook `apollo:auth` anymore bc `@nuxtjs/apollo` has no control anymore.)
const authLink = setContext(async (_, { headers }) => {
const someToken = '...'
return {
headers: {
...headers,
Authorization: `Bearer ${someToken}`,
},
}
})
// create an customLink as example for an custom manual link
const customLink = new ApolloLink((operation, forward) => {
return forward(operation).map((data) => {
return data
})
})
// Default httpLink (main communication for apollo)
const httpLink = createHttpLink({
uri: envVars.public.APOLLO_ENDPOINT,
useGETForQueries: true,
})
// Set custom links in the apollo client.
// This is the link chain. Will be walked through from top to bottom. It can only contain 1 terminating
// Apollo link, see: https://www.apollographql.com/docs/react/api/link/introduction/#the-terminating-link
$apollo.defaultClient.setLink(from([
errorLink,
authLink,
customLink,
httpLink,
]))
// For using useQuery in `@vue/apollo-composable`
provideApolloClient($apollo.defaultClient)
}) |
This solution works, but it seems rather hacky, given that in reality it is almost a matter of configuring apollo "from scratch", and at this point I don't really see the added value of installing nuxt apollo rather than apollo directly. The possibility to be able to change the endpoint(s) at runtime and not during the build seems to be quite common in the case of applications built once for multiple environments. Can we consider adding this possibility to the plugin? |
^ Would love to have this feature. Our app maintains multiple deployed subgraphs, being able to hot swap clients at runtime would be a huge benefit |
I've started looking at how to integrate runtime configuration. Locally with my tests, it seems to work pretty well. I don't know if this is the best approach. @Diizzayy, could you take a look at my commits here and tell me if this seems like a possible solution? Right now I've added a few @ts-ignore comments because I haven't been able to set the runtimeConfig type. I'm motivated to improve this solution and evolve the documentation accordingly. With this implementation, the clients would be configurable via nuxt runtimeConfig as follows: // nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxt/ui', '@nuxtjs/apollo'],
runtimeConfig: {
public: {
apollo: {
clients: {
default: {
httpEndpoint: 'https://my-custom-endoint.fr',
}
}
}
}
}
} And then if needed via an env variable (.env or system env variable): NUXT_PUBLIC_APOLLO_CLIENTS_DEFAULT_HTTP_ENDPOINT="http://test.com/graphql" |
Hello, Can we have on update on the native implementation of this feature ? @Diizzayy , has said in my previous comment, I would be happy to help. |
This is a sample for Nuxt 3, @nuxtjs/apollo module who need to authenticate WebSocket for Subscription. ( No Bearer token in my case, used "x-hasura-admin-secret" on my server to authenticate ). Link to apollo documentation for subscription // plugins/apollo.js
import { createHttpLink, from, split } from "@apollo/client/core";
import { RetryLink } from "@apollo/client/link/retry";
import { getMainDefinition } from "@apollo/client/utilities";
import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { onError } from "@apollo/client/link/error";
import { provideApolloClient } from "@vue/apollo-composable";
import { createClient } from "graphql-ws"; // Already import with @nuxtjs/apollo module
export default defineNuxtPlugin((nuxtApp) => {
// Optional method to get headers
const getHeaders = (full = false) => {
let hasura;
const token = localStorage.getItem("x-hasura-admin-secret")
if (token) hasura = atob(token);
const headers = full
? { headers: { "x-hasura-admin-secret": hasura.trim() || null } }
: { "x-hasura-admin-secret": hasura.trim() || null };
return headers;
}
const envVars = useRuntimeConfig();
const { $apollo } = nuxtApp;
// trigger the error hook on an error
const errorLink = onError((err) => {
nuxtApp.callHook("apollo:error", err);
});
const retryLink = new RetryLink({
delay: {
initial: 300,
max: 60000,
jitter: true,
},
// eslint-disable-next-line no-unused-vars
attempts: (count, operation, e) => {
if (e && e.response && e.response.status === 401) return false;
return count < 30;
},
});
const httpLink = createHttpLink({
uri: envVars.public.graphqlApi // http:// ou https://
});
const wsLink = new GraphQLWsLink(
createClient({
url: envVars.public.graphqlWss, // wss://
lazy: true,
connectionParams: () => ({
headers: getHeaders()
})
})
);
const splitLink = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === "OperationDefinition" &&
definition.operation === "subscription"
);
},
wsLink,
httpLink
);
$apollo.defaultClient.setLink(
from([errorLink, retryLink, splitLink])
);
provideApolloClient($apollo.defaultClient);
}); It's possible to set a simple configuration for apollo in nuxt.config.ts because main config is in custom plugin apollo.js // nuxt.config.ts
plugins: [
{ src: '~/plugins/apollo.js', mode: 'client' },
],
apollo: {
clients: {
default: {
connectToDevTools: true,
httpEndpoint: process.env.NUXT_PUBLIC_GRAPHQL_API as string,
wsEndpoint: process.env.NUXT_PUBLIC_GRAPHQL_WSS as string,
}
},
}, |
@TheYakuzo Thanks for the example. It helped me to override the configuration for the default client using Nuxt runtime config variables. Could you give an example for overriding the configuration for another client (not default) when working with multiple clients? |
For a Nuxt 3 app:
Is it possible to change the configuration of
httpEndpoint
andwsEndpoint
once the application is built, using the environment variables and the runtime configuration?Is there a plugin that allows this behaviour?
The text was updated successfully, but these errors were encountered: