Apollo Client and Environment Configuration
This guide explains how to properly set up Apollo Client in a React application using Vite, including environment variable configuration and best practices.
Table of Contents
- Basic Apollo Client Setup
- Environment Variables Configuration
- Advanced Apollo Client Configuration
- Integration with React
Basic Apollo Client Setup
The Apollo Client setup in your application is functional but could benefit from some enhancements. Here's a breakdown of your current implementation:
// src/config/apollo-client.ts
import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client";
const httpLink = new HttpLink({
uri: import.meta.env.VITE_BASE_URL,
});
const apolloClient = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
});
export default apolloClient;
Environment Variables Configuration
Your environment variable setup is correct:
// src/vite-env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_BASE_URL: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
// .env.local
VITE_BASE_URL="https://v3-symfony-app.oxagry.com/graphql";
Advanced Apollo Client Configuration
Here's an improved version of your Apollo Client setup with additional features:
// src/config/apollo-client.ts
import {
ApolloClient,
InMemoryCache,
HttpLink,
ApolloLink,
from,
} from "@apollo/client";
import { onError } from "@apollo/client/link/error";
// Error handling link
const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.forEach(({ message, locations, path }) => {
console.error(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
);
});
}
if (networkError) {
console.error(`[Network error]: ${networkError}`);
}
});
// HTTP connection to the API
const httpLink = new HttpLink({
uri: import.meta.env.VITE_BASE_URL,
// Include credentials if your API requires authentication
credentials: "include",
});
// Authentication middleware
const authMiddleware = new ApolloLink((operation, forward) => {
// Get the authentication token from local storage if it exists
const token = localStorage.getItem("token");
// Add the authorization to the headers
operation.setContext(({ headers = {} }) => ({
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
},
}));
return forward(operation);
});
// Cache configuration with type policies
const cache = new InMemoryCache({
typePolicies: {
// Example type policy for a Query field
Query: {
fields: {
// Example for a paginated field
items: {
// Concatenate results when fetching more items
keyArgs: false,
merge(existing = [], incoming) {
return [...existing, ...incoming];
},
},
},
},
},
});
// Initialize Apollo Client
const apolloClient = new ApolloClient({
link: from([errorLink, authMiddleware, httpLink]),
cache,
defaultOptions: {
watchQuery: {
fetchPolicy: "cache-and-network",
errorPolicy: "ignore",
},
query: {
fetchPolicy: "network-only",
errorPolicy: "all",
},
mutate: {
errorPolicy: "all",
},
},
});
export default apolloClient;
Integration with React
Your integration with React is correctly implemented:
// src/main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App.tsx";
import { ApolloProvider } from "@apollo/client";
import apolloClient from "@/config/apollo-client.ts";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<ApolloProvider client={apolloClient}>
<App />
</ApolloProvider>
</StrictMode>
);