2020-05-04
|~4 min read
|770 words
Things we’ll be covering:
I’m working in NextJS, so my sample client looks like the following:
import withApollo from "next-with-apollo"
import ApolloClient from "apollo-boost"
import { endpoint } from "../config"
function createClient({ headers }) {
return new ApolloClient({
uri: process.env.NODE_ENV === "development" ? endpoint : endpoint,
request: (operation) => {
operation.setContext({
fetchOptions: {
credentials: "include",
},
headers,
})
},
})
}
export default withApollo(createClient)
Walking through this step by step:
withApollo
is a higher order function designed to work specifically with NextJS. We will pass our createClient
function to it.
The ApolloClient
from apollo-boost
is the recommended way to get started with Apollo. It wraps up most of the useful features needed to start managing state with minimal configuration.
apollo-client
: Where all the magic happensapollo-cache-inmemory
: Our recommended cacheapollo-link-http
: An Apollo Link for remote data fetchingapollo-link-error
: An Apollo Link for error handling
The simplest client would look like:
import ApolloClient from "apollo-boost"
const client = new ApolloClient({
uri: "https://48p1r2roz4.sse.codesandbox.io",
})
I wanted a bit more, however, so I’ve added a custom request
configuration option. The docs say the following about this option:
This function is called on each request. It takes a GraphQL operation and can return a promise. To dynamically set
fetchOptions
, you can add them to the context of the operation withoperation.setContext({ headers })
. Any options set here will take precedence overfetchOptions
. Useful for authentication.
Notice, that’s exactly what I’ve done. The only modification I’ve made is to also configure fetchOptions
to include credentials (i.e. any cookie based credentials will be sent along for the ride on a request from the client.
Conceptually, this was described to me as similar to an “express middleware”. The big difference, however, is that we’re on the client side here. That means that we still have access to all localStorage
, cookies
, etc. and what we’re doing here is taking an operation and then modifying it. The specific modification in this case is that we’re injecting the headers and configuring our fetchOptions
.
Finally, we use our config
file to set our URI - in this case, it’s pointing to a backend GraphQL server.
According to the Getting Started guide, connecting our Apollo Client to React is done similarly to how you’d wrap a Redux store around React or connect a Context Provider.
In my case, it’s only marginally more complicated due to the fact I’m using NextJS:
import { Container } from "next/app"
import { Page } from "../components"
import { ApolloProvider } from "react-apollo"
import withData from "../lib/withData"
function App(props) {
const { apollo, Component } = props return (
<Container>
<ApolloProvider client={apollo}>
{" "}
<Page>
<Component />
</Page>
</ApolloProvider>
</Container>
)
}
export default withData(App)
withData
is a higher order function and so we wrap the App
with it to inject apollo
into our props.
That prop is then passed to our ApolloProvider
as the value for the client.
getInitialProps
enables server-side rendering in a page and allows you to do initial data population, it means sending the page with the data already populated from the server. This is especially useful for SEO .
Update: getInitialProps
was deprecated. It is now recommended to use getStaticProps
(for statically generation) or getServerSideProps
(for server side rendering). I’m using getInitialProps
however because I’m on version 7.0 of NextJS and these new methods are available on 9.3+.
function App(props) {
- const { apollo, Component } = props;
+ const { apollo, Component, pageProps } = props;
return (
<Container>
<ApolloProvider client={apollo}>
<Page>
- <Component />
+ <Component {...pageProps} />
</Page>
</ApolloProvider>
</Container>
);
}
+ App.getInitialProps = async ({ Component, ctx }) => {
+ let pageProps = {};
+ if (Component.getInitialProps) {
+ pageProps = await Component.getInitialProps(ctx);
+ }
+ // expose the query to the user
+ pageProps.query = ctx.query;
+ return { pageProps };
+ };
export default withData(App);
Also worth highlighting: ctx.query
is the query parameters from the URL, i.e. the ?key=value&otherKey=otherValue
part of example.com/pageTitle?key=value&otherKey=otherValue
.
When I say that this getInitialProps
“exposes the query to the user”, I mean that in the components that are rendered which receive the pageProps
, if there is any query parameter in the URL, it will be accessible as props.query.x
.
That’s it. We now have an Apollo Client connected to our backend and accessible from our client!
Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!