Next.js: ECONN refused when doing apollo graphQL query from getInitialProps

Created on 28 Jan 2019  路  5Comments  路  Source: vercel/next.js

Bug report

Describe the bug

Following the with-apollo-auth example
Successful behavior when I do client-side ApolloConsumer query. I pass the client through and query works.

Unsuccessful behavior when I attempt to do a server side query through getInitialProps. I pass the client through a handler that calls the same query and I get a ECONN refused error as shown below.

screen shot 2019-01-27 at 11 32 24 pm

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. I set up my ApolloClient in the init-apollo file as follows:
  const httpLink = createHttpLink({
    uri: 'http://localhost:8080/api/graphql',
    credentials: 'same-origin'
  })

  const authLink = setContext((_, { headers }) => {
    const token = getToken()
    return {
      headers: {
        ...headers,
        authorization: token ? `Bearer ${token}` : ''
      }
    }
  })

  return new ApolloClient({
    connectToDevTools: process.browser,
    ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
    link: ApolloLink.from([ authLink, httpLink ]),
    cache: new InMemoryCache().restore(initialState || {})
  })

  1. I set up my query as follows:
import gql from 'graphql-tag'

export default apolloClient => {
  apolloClient
    .query({
      query: gql`
        {
          getUser {
            id
          }
        }
      `
    })
    .then(({data}) => {
      console.log(data);
      return { userDetails: data.getUser }
    })
    .catch((err) => {
      // Fail gracefully
      console.log(err);
      return { userDetails: {} }
    })
  }
  1. I set up my getInitialProps function in the index.js file within the pages directory:
  import getUser from '../shared/services/get-user';

  static async getInitialProps (context) {
    const results = await getUser(context.apolloClient)
    console.log(results);
    return {}
  }

Expected behavior

I expect to see a log of the user returned, however I get an ECONNREFUSED error as shown above.

Screenshots

Screenshot above.

System information

  • OS: macOS Mojave
  • Browser (if applies) Chrome
  • Version of Next.js: 7.0.2
  • Version of ApolloClient: 2.4.12l

Additional context

  • Using Absinthe (Elixir+Phoenix) GraphQL API, url specified: http://localhost:8080/api/graphq
  • Using docker-compose to spin up multiple containers. API and NextJS client are in separate containers sitting behind nginx server. Nginx server routes to relevant container depending on the url endpoint specified. If url contains api, API container will be called.

Most helpful comment

@timneutkens How can it lose connection the moment I put it in getInitialProps is my question. I also noticed when I do async await on any function, it loses connection. As soon as I remove that, the backend call proceeds to execute.

All 5 comments

ECONNREFUSED is a network error meaning there is nothing listening/replying on the specific url.

@timneutkens How can it lose connection the moment I put it in getInitialProps is my question. I also noticed when I do async await on any function, it loses connection. As soon as I remove that, the backend call proceeds to execute.

@sc4224 having the same problem, I think you are using docker-compose too. We need to change localhost to the service name of the api server if SSR

@timneutkens, @K-JHC is right. Unfortunately if you are using docker-compose, containers can talk to each other by using service name or ip. So instead of using localhost:3000/graphql you have to use serviceName|IP:3000/graphql in your network. o now I found next solution:

  1. .env + dynamic client.urldepends on browser/server request (localhost:3000 || serviceName:3000) -> sounds like workaround for me :(
  2. Some proxy or mappping serviceName < - > localhost inside containers.

Hard topic basically.

There is an easy workaround for this, but it's ugly.

Manually change the HTTP Link uri depending on if the call is happening on the front end

export const isServer = () => typeof window === `undefined`;
const fetchHack = (...args) => {
  const shouldRewriteUri = !isServer() && process.env.API_URI_DOCKER && process.env.NODE_ENV === `development`;
  if (shouldRewriteUri)
    args[0] = args[0].replace(process.env.API_URI, process.env.API_URI_DOCKER);
  return fetch(...args);
};
const httpLink = new HttpLink({
    uri: `${process.env.API_URI}/graphql`,
    fetch: fetchHack, 
  });
Was this page helpful?
0 / 5 - 0 ratings

Related issues

wagerfield picture wagerfield  路  3Comments

DvirSh picture DvirSh  路  3Comments

kenji4569 picture kenji4569  路  3Comments

formula349 picture formula349  路  3Comments

sospedra picture sospedra  路  3Comments