lopezjurip / routed-react

Using create-react-app with React Router + Express.js and Docker. This is a naive and simple way where server-side rendering is not required.
https://medium.com/@patriciolpezjuri/using-create-react-app-with-react-router-express-js-8fa658bf892d
110 stars 31 forks source link

How do I set up backend routes in Express? #1

Closed yongzhihuang closed 8 years ago

yongzhihuang commented 8 years ago

Hi!

Awesome project btw. I would like to set up certain routes in express and have express handle them rather than React Router, how would I go about doing this?

Example:

app.get('/api/v1/test', (req, res) => {
  res.json({
    staus: 200
  });
});

Thanks!

lopezjurip commented 8 years ago

It's really easy, take a look at server/app.js:

const app = express();

// ...

// Add anything you want before '*'
app.get('/api/v1/test', (req, res) => {
  res.json({
    staus: 200
  });
});

app.use(express.static(path.resolve(__dirname, '..', 'build')));

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

module.exports = app;
yongzhihuang commented 8 years ago

Hmm, I did that but that route is still being handled by react router it seems...

lopezjurip commented 8 years ago

Oh now I get your question. The react development server runs at port 3000 (npm start), but the express.js server runs at port 9000 and it only returns the compiled react app (`npm run start:server).

Performing a GET request with fetch works fine:

class App extends Component {
  // ...
  state = {}

  componentWillMount() {
    fetch('http://localhost:9000/api/v1/test')
      .then(result => result.json())
      .then(response => this.setState({ response }));
  }

  render() {
    // ...
  }
}

But it is necessary to allow CORS because in development we have two apps on different ports:

const cors = require('cors');

const app = express();
if (process.env.NODE_ENV !== 'production') {
  app.use(cors());
}

it would be necessary to build the app (npm run build) each time to make it work at port 9000.

yongzhihuang commented 8 years ago

Ah makes sense now, thank you very much!

nooralasa commented 7 years ago

Hi,

I'm running into a similar issue. I'm doing OAuth authentication with github and I redirect to the github page from the server side. My server.js looks like this:

//... authentication logic with passport.js ... //

app.get('auth/github', 
  passport.authenticate('github', {scope: ['user', 'public_repo']})
);

app.use(express.static(path.join(__dirname, '/lemon/build')));

app.get('*', 
  function(req, res) {
    res.sendFile(path.join(__dirname+'/lemon/build/index.html'));
  });

My React App is as follows:

// ... importing modules ... //

ReactDOM.render(
    <Provider store={store}>
        <Router history={browserHistory}>
            <Route path="/" component={LandingPage} />
            <Route path="/announcements" component={AnnouncementsContainer} />
            <Route path="/courses" component={CoursesContainer} />
            <Route path="/community" component={CommunityContainer} />
            <Route path="/404" component={NotFoundPage} />
        </Router>
    </Provider>,
    document.getElementById('root')
);

I build the react app and serve it statically. I want the user to be able to navigate to localhost:3001/auth/github (server running on port 3001) which would redirect the user to github to login. However, instead it renders an empty page (index.html from my static files).

What I don't seem to understand is why the middleware is not being applied in order. That is why is the url redirected to the static files and not the auth/github routing which is specified first? I think it has to do with browser caching, but I tried disabling caching and that didn't help:

app.use(express.static(path.join(__dirname, '/lemon/build'), { etag: false }));

Any help would be really appreciated.

lopezjurip commented 7 years ago

Probably you are missing the callback route:

const middleware = passport.authenticate('github', {
  failureRedirect: '/login', // clientside route
});

app.get('/auth/github/callback', middleware, (req, res) => {
  res.redirect('/'); // clientside route
});
nooralasa commented 7 years ago

No I do have that part but I didn't include it in the earlier comment. Here is what it looks like:

app.get('auth/github/callback', 
  passport.authenticate('github', { failureRedirect: '/' }),
  function(req, res) {
    console.log('Successful login!');
    res.redirect('/announcements');
  }
);

The issue is that localhost:3001/auth/github will not redirect to github and would render my static files. It redirects if I comment out the middleware handling serving the static assets. Any thoughts on why that could be the case?