GraphQL only works on production when also running localhost and Apollo Client is set to localhost only

GraphQL only works on production when also running localhost and Apollo Client is set to localhost only


1

Im working an app using react for the frontend and apollo/client and graphql. It works perfectly on the localhost, but when I deploy to heroku it only works if I also have the app running on the localhost.
Here is what I have for the uri.

const client = new ApolloClient({
  uri: 'https://localhost:5000/graphql',
  cache: new InMemoryCache(),
});

I tried setting the uri localhost then if in production to set it to heroku:

let uri = https://localhost:5000/graphql
if (process.env.NODE_ENV === 'production') {
   uri = https://denver-judo.herokuapp.com/graphql
}

I also tried uri = https://denver-judo.herokuapp.com/${PORT}/graphql but nothing works.

This is my app.js file

import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
import { useState } from 'react';
import {
  Route,
  Routes,
  BrowserRouter as Router,
  Outlet,
} from 'react-router-dom';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import HomeScreen from './screens/HomeScreen';
import Container from 'react-bootstrap/Container';
import Navbar from 'react-bootstrap/Navbar';
import Nav from 'react-bootstrap/Nav';
import { LinkContainer } from 'react-router-bootstrap';
import Button from 'react-bootstrap/Button';
import AboutScreen from './screens/AboutScreen';
import AdminScreen from './screens/AdminScreen';

// Construct main GraphQL API endpoint
let uri = 'https://localhost:5000/graphql';
if (process.env.NODE_ENV === 'production') {
  uri = `https://denver-judo.herokuapp.com/api/graphql`;
}
console.log(process.env.NODE_ENV);
console.log(uri);
const client = new ApolloClient({
  uri: uri,
  cache: new InMemoryCache(),
});
function App() {
  const location = window.location.pathname;
  const [sidebarIsOpen, setSidebarIsOpen] = useState(false);

  return (
    <ApolloProvider client={client}>
      <Router>
        <div
          className={
            sidebarIsOpen
              ? 'site-container active-cont d-flex flex-column'
              : 'site-container d-flex flex-column'
          }
        >
          <ToastContainer position="top-center" limit={1} />
          <header>
            <Navbar
              expand="lg"
              className={`navbar navbar-dark ${
                location === '/' ? 'navbar-custom' : 'navbar-custom-light'
              }`}
            >
              <Container>
                <LinkContainer to="/">
                  <Navbar.Brand>
                    <img
                      className="ms-4"
                      src={
                        location === '/'
                          ? 'assets/img/DJ-logo-black.png'
                          : 'assets/img/DJ-logo-white.png'
                      }
                      alt="Denver Judo"
                      style={{ width: '60px' }}
                    />{' '}
                  </Navbar.Brand>
                </LinkContainer>
                <h1
                  className={
                    location === '/'
                      ? 'navTitle-dark text-center'
                      : 'navTitle text-center'
                  }
                >
                  Denver Judo
                </h1>

                <Button
                  style={{
                    backgroundColor: location === '/' ? '#d9d9d9' : '#262626',
                  }}
                  onClick={() => setSidebarIsOpen(!sidebarIsOpen)}
                  className="me-4"
                >
                  <i
                    className="fa fa-bars fa-lg"
                    style={{
                      color: location === '/' ? '#262626' : '#d9d9d9',
                    }}
                  ></i>
                </Button>
              </Container>
            </Navbar>
          </header>
          <div
            className={
              sidebarIsOpen
                ? 'active-nav side-navbar d-flex justify-content-between flex-wrap flex-column'
                : 'side-navbar d-flex justify-content-between flex-wrap flex-column'
            }
          >
            <Nav className="flex-column text-white w-100 p-2">
              <Nav.Item>
                <strong>Denver Judo</strong>
              </Nav.Item>
              <LinkContainer to="/" onClick={() => (this.expand = '')}>
                <Nav.Link
                  className={
                    location === '/' ? 'nav-text nav-text-bold' : 'nav-text'
                  }
                >
                  Home
                </Nav.Link>
              </LinkContainer>
              <LinkContainer to="/schedule" onClick={() => (this.expand = '')}>
                <Nav.Link
                  className={
                    location === '/schedule'
                      ? 'nav-text nav-text-bold'
                      : 'nav-text'
                  }
                >
                  Schedule
                </Nav.Link>
              </LinkContainer>
              <LinkContainer to="/about" onClick={() => (this.expand = '')}>
                <Nav.Link
                  className={
                    location === '/about'
                      ? 'nav-text nav-text-bold'
                      : 'nav-text'
                  }
                >
                  About
                </Nav.Link>
              </LinkContainer>
            </Nav>
            <Outlet />
          </div>
          <main>
            <Routes>
              <Route index element={<HomeScreen />} />
              <Route path="/about" element={<AboutScreen />} />
              <Route path="_admin/*" element={<AdminScreen />} />
            </Routes>
          </main>
          <footer>
            <div className="text-center">
              Denver Judo
              <br />
              All rights reserved
            </div>
          </footer>
        </div>
      </Router>
    </ApolloProvider>
  );
}

export default App;

Here is the server.js from the backend:

const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const path = require('path');
const dotenv = require('dotenv');
const { typeDefs, resolvers } = require('./schemas');
const db = require('./config/connection');
require('dotenv');

dotenv.config();

const PORT = process.env.PORT || 5000;
const app = express();

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

console.log(process.env.NODE_ENV);
if (process.env.NODE_ENV === 'production') {
  app.use(express.static(path.join(__dirname, '../client/build')));

  app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname, '../client/build/index.html'));
  });
}

// Create a new instance of an Apollo server with the GraphQL schema
const startApolloServer = async (typeDefs, resolvers) => {
  await server.start();
  server.applyMiddleware({ app });

  db.once('open', () => {
    app.listen(PORT, () => {
      console.log(`API server running on port ${PORT}!`);
      console.log(
        `Use GraphQL at https://localhost:${PORT}${server.graphqlPath}`
      );
    });
  });
};

// Call the async function to start the server
startApolloServer(typeDefs, resolvers);

3

  • What does your Procfile look like, as well as your index.js that starts ApolloServer?

    – Wesley LeMahieu

    Feb 19 at 5:30

  • I updated the question with the app.js file where I have the apollo ApolloServer code but I don't hae a Procfile. I've never used one but haven't had this problem before.

    – Stephen Scott Moore

    Feb 19 at 13:21

  • Are you on Apollo 3 or 4?

    – Wesley LeMahieu

    Feb 19 at 15:53

2 Answers
2


0

It seems you are trying to access but aren’t setting the /api/graphql path. Also the apollo-server-express library is depreciated. I recommend following the Migrating to Apollo Server 4 guide which highlights how to set the graphql path using app.use. Otherwise the default graphql path is / in v3. In v4 it’s /graphql.

In v4 it’s set like this:

app.use(
  '/graphql',
  cors<cors.CorsRequest>(),
  json(),
  expressMiddleware(server, {
    context: async ({ req }) => ({ token: req.headers.token }),
  }),
);


0

You have CORS issue. So you should allow cross origin requests.

const cors = require('cors')
app.use(cors())

Your frontend prod is available on Heroku URL
https://denver-judo.herokuapp.com/api/graphql
The backend on both envs is listened on https://localhost:PORT

So the client side makes requests to the different host
https://denver-judo.herokuapp.com/api/graphql => https://localhost:PORT
and browser is blocking it due to security risks (CORS policy)

This worked for my Angular+Nestjs+Graphql application.



Leave a Reply

Your email address will not be published. Required fields are marked *