Accessing ctx, headers from inside withApollo export causes ctx to be undefined inside of WithApollo.getInitialProps.
See original GitHub issueI’m trying to access a token from a cookie and set it to the headers for authorization. When trying to access ctx and headers properties through the withApollo export, I get the following error:
_app.js:7 Uncaught TypeError: Cannot read property 'req' of undefined
at nextCookies (index.js:8)
at push../lib/withApollo.js.__webpack_exports__.default.next_with_apollo__WEBPACK_IMPORTED_MODULE_9___default.render (withApollo.js:7)
at getClient (apollo.js:23)
at Object.initApollo [as default] (apollo.js:14)
at WithApollo(Profile) (withApollo.js:23)
at renderWithHooks (react-dom.development.js:16260)
at mountIndeterminateComponent (react-dom.development.js:18794)
at beginWork$1 (react-dom.development.js:20162)
at HTMLUnknownElement.callCallback (react-dom.development.js:336)
at Object.invokeGuardedCallbackDev (react-dom.development.js:385)
at invokeGuardedCallback (react-dom.development.js:440)
at beginWork$$1 (react-dom.development.js:25780)
at performUnitOfWork (react-dom.development.js:24695)
at workLoopSync (react-dom.development.js:24671)
at performSyncWorkOnRoot (react-dom.development.js:24270)
at scheduleUpdateOnFiber (react-dom.development.js:23698)
at updateContainer (react-dom.development.js:27103)
at react-dom.development.js:27528
at unbatchedUpdates (react-dom.development.js:24433)
at legacyRenderSubtreeIntoContainer (react-dom.development.js:27527)
at Object.hydrate (react-dom.development.js:27591)
at renderReactElement (index.js:31)
at doRender$ (index.js:38)
at tryCatch (runtime.js:45)
at Generator.invoke [as _invoke] (runtime.js:271)
at Generator.prototype.<computed> [as next] (runtime.js:97)
at tryCatch (runtime.js:45)
at invoke (runtime.js:135)
at runtime.js:170
at new Promise (<anonymous>)
at callInvokeWithMethodAndArg (runtime.js:169)
at AsyncIterator.enqueue [as _invoke] (runtime.js:192)
at AsyncIterator.prototype.<computed> [as next] (runtime.js:97)
at Object.push../node_modules/regenerator-runtime/runtime.js.exports.async (runtime.js:216)
at doRender (index.js:34)
at render$ (index.js:18)
at tryCatch (runtime.js:45)
at Generator.invoke [as _invoke] (runtime.js:271)
at Generator.prototype.<computed> [as next] (runtime.js:97)
at tryCatch (runtime.js:45)
at invoke (runtime.js:135)
at runtime.js:170
at new Promise (<anonymous>)
at callInvokeWithMethodAndArg (runtime.js:169)
at AsyncIterator.enqueue [as _invoke] (runtime.js:192)
at AsyncIterator.prototype.<computed> [as next] (runtime.js:97)
at Object.push../node_modules/regenerator-runtime/runtime.js.exports.async (runtime.js:216)
at render (index.js:18)
at next-dev.js:4
at fouc.js:4
From what I can tell it seems like it’s erroring on ctx.req in the WithApollo.getInitialProps from /next-with-apollo/lib/withApollo
WithApollo.displayName = `WithApollo(${getDisplayName(Page)})`;
if (getInitialProps || getDataFromTree) {
WithApollo.getInitialProps = async (pageCtx) => {
const ctx = 'Component' in pageCtx ? pageCtx.ctx : pageCtx;
const { AppTree } = pageCtx;
const headers = ctx.req ? ctx.req.headers : {};
const apollo = apollo_1.default(client, { ctx, headers });
const apolloState = {};
let pageProps = {};
if (getInitialProps) {...
Here’s where I’m trying to access the token and set the headers
import withApollo from 'next-with-apollo';
import ApolloClient, { InMemoryCache } from 'apollo-boost';
import { ApolloProvider } from '@apollo/react-hooks';
import Cookie from 'next-cookies'
export default withApollo(
({ initialState, ctx, headers }) => {
const { token } = Cookie(ctx)
return new ApolloClient({
uri: 'https://graphql.api.com',
cache: new InMemoryCache().restore(initialState || {}),
headers: {
...headers,
authorization: token ? `Bearer ${token}` : ''
}
});
},
{
render: ({ Page, props }) => {
return (
<ApolloProvider client={props.apollo}>
<Page {...props} />
</ApolloProvider>
);
}
}
);
Here’s some example components trying to use them
import { useQuery } from '@apollo/react-hooks'
const ProfileCard = ({ id }) => {
const GET_USER = gql`
{
user (id: $id) {
id
name
email
}
}
`
const { loading, error, data } = useQuery(GET_USER, { variables: { id })
if (loading) return <div>loading ...</div>
if (error) return <div>Error</div>
const { name, email } = data
return (
<ul>
<li>
Id: {name} */}
</li>
<li>
Name: {email} */}
</li>
</ul>
)
}
export default ProfileCard
import Layout from '../../components/Layout'
import ProfileCard from '../../components/ProfileCard'
import withApollo from '../../lib/withApollo'
import { getDataFromTree } from '@apollo/react-ssr'
function Profile({ id }) {
return (
<Layout>
<ProfileCard id={id} />
</Layout>
)
}
export default withApollo(Profile, { getDataFromTree })
I’m fairly certain it’s something I’m doing wrong, but I can’t spot it. I’ve tried with and without getDataFromTree (even though initalState, ctx, and headers are undefined client side). If I remove the ctx and header properties from the destructuring, and hard code the token, it functions. After going over the apollo docs, this is what seemed to be the correct method. How should I be trying to access these?
Issue Analytics
- State:
- Created 4 years ago
- Comments:6 (2 by maintainers)
Top GitHub Comments
Thank you for all the help. I got it to work with:
Where I’m assuming
js-cookie
is reading thedocument.cookie
. This is my first non-trivial Next app and the first time I’ve used Apollo at all, so it’s been a big learning curve.@DoubleBridges
ctx
andheaders
are only for the server, once you’re in the browser (after the first render with SSR) you don’t need to access those objects, the cookie will be sent by the browser if you usecredentials: 'same-origin'
orcredentials: 'include'
.If you need to send the cookie inside the
authorization
header usedocument.cookie
once you’re in the browser instead ofctx
.If your cookie is
httpOnly
(not available indocument.cookie
) then don’t use theauthorization
header.