question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Demonstrate Apollo-Server context usage with-apollo-xxx examples

See original GitHub issue

Feature 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:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:10 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
eric-burelcommented, Mar 17, 2020

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.

1reaction
eric-burelcommented, Mar 17, 2020

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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Demonstrate Apollo-Server context usage with-apollo ... - GitHub
Current with-apollo- examples demonstrate how to read user data in local (leaf) resolvers which is not production-like. Luckily, SchemaLink ...
Read more >
Contribute to vercel/next.js · GitHub
More than 83 million people use GitHub to discover, fork, and contribute to over ... Demonstrate Apollo-Server context usage with-apollo-xxx examples good ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found