Demonstrate Apollo-Server context usage with-apollo-xxx examples
See original GitHub issueFeature request
Current with-apollo-
examples do not demonstrate how to use Apollo-Server with context
resolver. It doesn’t work out of the box and it’s not at all straightforward for Apollo newbies (like myself) how to enable it.
Note: this is a request for help/consulting for Apollo experts.
1. createIsomorphLink
createIsomorphLink
implementations recommended by Apollo Team imply the use of
SchemaLink
on server and HttpLink
on client. SchemaLink
is said to be more performant
because it avoids HTTP layer alltogether:
function createIsomorphLink(ctx) {
if (typeof window == 'undefined') {
// !!! Server side
let {SchemaLink} = require('apollo-link-schema')
let {schema, context} = require('./schema')
return new SchemaLink({schema, context : ctx})
} else {
// !!! Browser side
let {HttpLink} = require('apollo-link-http')
return new HttpLink({
uri: '/api/graphql',
credentials: 'same-origin',
})
}
}
2. SchemaLink
SchemaLink
does not initiate an HTTP request. The side effect is that Apollo-Server context
function is never called. This function is crucial as it usually fetches or polyfills all common resolver’s data including current user/visitor, etc. Current with-apollo-
examples demonstrate how to read user data in local (leaf) resolvers which is not production-like.
Luckily, SchemaLink
accepts a context
argument where we can provide the same context
resolver as to the new ApolloServer({context: ...})
.
3. Two calls
Now the tricky part is that createIsomorphLink
is called twice. Once with {req, res}
context data (coming from getInitialProps
) and another – with no context (coming from these:
const WithApollo = ({ apolloClient, apolloState, ...pageProps }) => {
const client = apolloClient || initApolloClient(undefined, apolloState) // !!!
lines).
context
function of Apollo-Server must not be called with empty context as it, in most cases, reads ctx.req
.
The second invocation of Apollo-Client will reuse cache so resolvers, including context
won’t be called. It seems to me that an update like:
function createIsomorphLink(ctx) {
...
- let {schema} = require('./schema')
- return new SchemaLink({schema, context: ctx)
+ let {schema, context} = require('./schema')
+ return new SchemaLink({schema, context : isEmpty(ctx) ? context(ctx) : ctx})
}
should be enough to enable Server’s context
usage. Given that apollo/schema.js
exports standalone context
function of course.
I can make a PR but, before that, it would be great to get a feedback from someone more experienced with Apollo and NextJS.
Are my reasoning correct? Is my proposal valid?
Another option it to always use HttpLink
like it’s done in https://github.com/adamsoffer/next-apollo and https://github.com/lfades/next-with-apollo For some reason the authors of both packages decided to not rely on SchemaLink
…
Issue Analytics
- State:
- Created 4 years ago
- Reactions:1
- Comments:10 (7 by maintainers)
Top GitHub Comments
Btw I do not agree with the “good-first-issue” tag, this is trickier than it seems and raises questions about state-of-the-art patterns like isomorphic code. There is no clear consensus about how to manage such issues.
Hi, just to give feedback we use
SchemaLink
in Vulcan without much trouble as far as I know. We define different clients for SSR and client-side rendering, literally in different files.Having worked with isomorphic code and SSR for a while, we now tend to consider calls like
ssr: Boolean(ctx)
to be anti-pattern, except if you really can’t avoid it or it’s done in a “clean” and limited manner like in Next pages.This is because server-side code tend to diverge slowly from client-side code, and it becomes unmanageable in an app that is multiple years old (unclear bundling process,
require()
everywhere). Even if it look alike in the beginning you quickly hit issues like needing different link depending on the environment. The first time you wonder “am I server-side?” in your code is probably the good time to split your file in 2 for client and server. (edit: or most of the time 3 files, one for common code, and 2 smaller files with specific code for each env)An important step is to unify context between REST calls (here the API routes), graphQL calls server side, and graphQL calls client-side. For some reason using a context in queries is not that common in traditional Node app. As far as I understand that’s the point of this issue.