Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing internal API with React, Axios on Heroku

I am building a full stack React application that accesses its own back end API with Axios. In my local environment, the following works as expected, with the server responding with JSON data, which is then rendered properly.

axios.get('/api/questions/categories')

I deployed to Heroku, and the app is launching normally and MongoDB is connected. Now, when the same GET request is made, it is not reaching the back end. When I log the response from Axios to the console, it contains the actual HTML of the page, instead of the JSON object expected.

For further clarification, if I manually type 'http://localhost:8080/api/questions/categories' in the address bar, the expected JSON data is displayed. If I do the same with the app on Heroku, I see that a '#' is appended to the url and the page display does not change, no error messages. This leads me to think that react-router is involved, but I have not been able to figure out how/why.

My stack: Node, Express, Mongo, React

Not using Redux

Using Axios to call my own API

// Dependencies
var express = require('express');
var path = require('path');
var webpack = require('webpack');
var webpackMiddleware = require('webpack-dev-middleware');
var webpackHotMiddleware = require('webpack-hot-middleware');
var config = require('./webpack.config.js');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var morgan = require('morgan');

var inDev = process.env.NODE_ENV !== 'production';
var port = inDev ? 8080 : process.env.PORT;
var app = express();

// MIDDLEWARE

if (inDev){
  var compiler = webpack(config);
  var middleware = webpackMiddleware(compiler, {
    publicPath: config.output.publicPath,
    contentBase: 'app',
    stats: {
      colors: true,
      hash: false,
      timings: true,
      chunks: false,
      chunkModules: false,
      modules: false
    }
  });

  app.use(morgan('dev'));
  app.use(middleware);
  app.use(webpackHotMiddleware(compiler));
  app.get('/', function response(req, res) {
    res.write(middleware.fileSystem.readFileSync(path.join(__dirname,     'dist/index.html')));
    res.end();
  });
} else {
  app.use(express.static(__dirname + '/dist'));
  app.get('*', function response(req, res) {
    res.sendFile(path.join(__dirname, 'dist/index.html'));
  });
}

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

app.use(function(req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Credentials', 'true');
  res.setHeader('Access-Control-Allow-Methods',     'GET,HEAD,OPTIONS,POST,PUT,DELETE');
  res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers,  Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method,   Access-Control-Request-Headers');

  //and remove caching so we get the most recent comments
  res.setHeader('Cache-Control', 'no-cache');
  next();
});

// DATABASE

var dbPath = inDev ? 'mongodb://localhost/quizMe' :     'mongodb://heroku_pmjl5579:[email protected]:43000/heroku_pmjl5579';

mongoose.connect(dbPath);

// ROUTING / API

// var indexRoute = require('./routes/index');
var questionsRoute = require('./routes/api/questions');
// app.use('/', indexRoute);
app.use('/api/questions', questionsRoute);

app.listen(port, function(){
  console.log('Express server up on ' + port);
});

Thanks for any help!

like image 276
gJanssen Avatar asked Mar 26 '17 23:03

gJanssen


1 Answers

Most single page applications route all requests to the root path and let the front end router take over. I suspect that is what is happening to your app.

Do you have any form of requests redirection logic in your back end code or any server configuration code?

What you can do is to whitelist some paths that you don't want front end routing to take over, such as those that start with /api. Pasting your server side config here will be helpful.

In your server config, when inDev is false, you have a app.get('*', ...) that catches all requests and responds with the static single page app. Hence API requests will also give the same response. You will need to restructure your routes to match /api before the wildcard *. Some examples can be found here

like image 184
Yangshun Tay Avatar answered Sep 19 '22 23:09

Yangshun Tay