Next.js: with-apollo-auth example not working

Created on 24 May 2019  路  7Comments  路  Source: vercel/next.js

Example name

Example name is with-apollo-auth

Examples bug report

I implemented the with-apollo-auth example. See this repo.

Every query is now Server Side Rendered using getDataFromTree, but... not one query. The me query, that is based on authentication cookie doesn't work at all.

When I didn't use the example and was happy with Client Side Rendering, the cookie and me query rendered properly. But, on SSR... backend doesn't look like is sending any cookie.

Here's the complete backend repo.

To Reproduce

  1. Clone this repo.
  2. Make https://paprink-server.herokuapp.com the endpoint.
  3. See all queries work but not me query.
  4. See the console logged variable loggedInUser be undefined.

Expected behavior

The expected behaviour was to see the paprinkToken cookie being parsed.

System information

  • OS: MacOS Mojave
  • Browser Chrome Latest
  • Version of Next.js: v8.1.0

Additional context

Have you tried the example? I saw the example uses graphcool but it isn't clear about how you get the cookie.

good first issue

Most helpful comment

Experiencing the same issue

All 7 comments

Experiencing the same issue

Would appreciate an investigation of the issue posted 馃憤

I've marked it as good first issue. There is no need to keep pinging on open issues.

with-apollo-auth example wasn't working... so to cater the needs...
Harshit Pant helped me by writing this code.

init-apollo.js 馃憞

import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { HttpLink } from 'apollo-link-http'
import { ApolloLink } from 'apollo-link'
import { onError } from 'apollo-link-error'
import { setContext } from 'apollo-link-context'
import fetch from 'isomorphic-unfetch'

// import { WebSocketLink } from 'apollo-link-ws'
// import { getMainDefinition } from 'apollo-utilities'

const httpLink = new HttpLink({
  uri: `${process.env.ENDPOINT}/api/graphql`,
  credentials: 'include',
})
const cache = new InMemoryCache()

let link = null

if (process.browser) {
  const errorLink = onError(({ graphQLErrors, networkError }) => {
    if (graphQLErrors) {
      graphQLErrors.map(({ message, locations, path }) =>
        // tslint:disable-next-line:no-console
        console.log(
          `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
        ),
      )
    }
    if (networkError) {
      // tslint:disable-next-line:no-console
      console.log(`[Network error]: ${networkError}`)
    }
  })

  link = ApolloLink.from([errorLink, httpLink])
}

let apolloClient = null

// Polyfill fetch() on the server (used by apollo-client)
if (!process.browser) {
  global.fetch = fetch
}

function create(initialState, cookie = null) {
  const authLink = setContext((_, { headers }) => {
    return {
      headers: {
        ...headers,
        Cookie: cookie,
      },
    }
  })
  return new ApolloClient({
    connectToDevTools: process.browser,
    ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
    link: process.browser ? link : authLink.concat(httpLink),
    cache: cache.restore(initialState || {}),
  })
}

export default function initApollo(initialState, cookie) {
  // Make sure to create a new client for every server-side request so that data
  // isn't shared between connections (which would be bad)
  if (!process.browser) {
    return create(initialState, cookie)
  }

  // Reuse client on the client-side
  if (!apolloClient) {
    apolloClient = create(initialState)
  }

  return apolloClient
}

with-apollo-client.js 馃憞

import React from "react";
import initApollo from "./init-apollo";
import Head from "next/head";
import { getDataFromTree } from "react-apollo";


export default App => {
  return class Apollo extends React.Component {
    static displayName = "withApollo(App)";
    static async getInitialProps(ctx) {
      const { Component, router } = ctx;

      let appProps = {};
      if (App.getInitialProps) {
        appProps = await App.getInitialProps(ctx);
      }

      const apolloState = {};
      const apollo = !process.browser
        ? initApollo(null, ctx.ctx.req.headers.cookie)
        : initApollo();
      // Run all GraphQL queries in the component tree
      // and extract the resulting data
      try {
        // Run all GraphQL queries
        await getDataFromTree(
          <App
            {...appProps}
            Component={Component}
            router={router}
            apolloState={apolloState}
            apolloClient={apollo}
          />
        );
      } catch (error) {
        // Prevent Apollo Client GraphQL errors from crashing SSR.
        // Handle them in components via the data.error prop:
        // http://dev.apollodata.com/react/api-queries.html#graphql-query-data-error
        console.error("Error while running `getDataFromTree`", error);
      }

      if (!process.browser) {
        // getDataFromTree does not call componentWillUnmount
        // head side effect therefore need to be cleared manually
        Head.rewind();
      }

      // Extract query data from the Apollo store
      apolloState.data = apollo.cache.extract();

      return {
        ...appProps,
        apolloState
      };
    }
    constructor(props) {
      super(props);
      // `getDataFromTree` renders the component first, the client is passed off as a property.
      // After that rendering is done using Next's normal rendering pipeline
      this.apolloClient =
        props.apolloClient || initApollo(props.apolloState.data);
    }

    render() {
      return <App {...this.props} apolloClient={this.apolloClient} />;
    }
  };
};

_app.js 馃憞

import React from 'react'
import App, { Container } from 'next/app'
import { ApolloProvider } from 'react-apollo'

import withData from '../src/lib/with-apollo-client'
import Page from '../src/components/Page'

class Wrapper extends App {

    static async getInitialProps({Component, ctx}){

        let pageProps = {}
        if(Component.getInitialProps){
            pageProps = await Component.getInitialProps(ctx)
        }

        // This exposes query to the user
        pageProps.query = ctx.query
        return { pageProps }

    }

    render() {
        const { Component, apolloClient, pageProps } = this.props

        return (
            <Container>
                <ApolloProvider client={apolloClient}>
                    <Page>
                        <div className="super_container"><Component {...pageProps} /></div>
                    </Page>
                </ApolloProvider>
            </Container>
        )
    }

}

export default withData(Wrapper)

That code, somehow similar to yours... implements the same thing differently which allows cookies to be rendered.

Here's the complete code for you to follow on and change with-apollo-auth example.

I'm quite confused with this issue - it doesn't seem to target with-apollo-auth example but focuses on the problem you have in application. I also see the error that there's no user which isn't surprising given I haven't made account yet. Are you sure you're correctly sending cookie to backend. The code you've provided seem to take a different approach at parsing cookies.

The thing is - I'm still not sure what's wrong with the example.

As far as example alone I keep on receiving issue that 'net' module is not found for https-proxy-agent. I'm not sure if I should create separate issue or do it here?

I'll close this because it sounds like OP solved their issue. @masives, please open a separate issue or PR for that! 馃檹

Hey @masives, the problem is that cookie won't render even after the signup... And in the example, there is no reference of how signin takes place.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

havefive picture havefive  路  3Comments

formula349 picture formula349  路  3Comments

DvirSh picture DvirSh  路  3Comments

kenji4569 picture kenji4569  路  3Comments

irrigator picture irrigator  路  3Comments