Setting up React Router with Express - node.js

I have a few questions on setting up React with Express.
First, I used the same route paths for both Express and React-Router. I thought these were supposed to match up. But when I navigate to a page, api/blogPosts, it just shows the JSON format of data that I fetched from MongoDB. That is, the Express route overrides the React view. I know that I could just modify the route path in React-Router (for example, without 'api' in front) so that there are different routes. Then it will show the React view as expected, while still making the api calls. But again, I thought that the route paths were supposed to match up. How should I handle this properly?
Second, I used express.Router() and I'm not sure this is necessary. When should I use express.Router() and when should I just use app.get, app.post, etc.
Third, when people discuss client side routing are they discussing things like React Router? When people discuss server-side routing are they just referring to making api calls to the database like the apiRouter calls?
routes.js
<Route component={App}>
<Route path='/' component={Home} />
<Route path='/api/blogPosts/create' component={Create} />
<Route path='/api/blogPosts/:blogPostId' component={BlogPost} />
</Route>
server.js
var apiRouter = express.Router();
apiRouter.route('/blogPosts')
.post(function(req, res) {
var blogPost = new BlogPost();
blogPost.postbody = req.body.postbody;
blogPost.save(function(err) {
if (err) {
return res.send(err);
}
res.json({ message: blogPost.postbody + "created"})
});
})
.get(function(req, res) {
BlogPost.find(function(err, posts) {
if (err) return res.send(err);
res.json(posts);
});
});
apiRouter.route('/blogPosts/:blogPostId')
.get(function(req, res) {
BlogPost.findById(req.params.blogPostId, function(err, blogPost) {
if (err) return res.send(err);
res.json(blogPost);
})
});
app.use('/api', apiRouter);

So from my experience React Router is for client side routing for a single page application. Meaning it uses the browser's history api to make it appear like the browser is going to different routes without actually leaving the original page. The express routing is server side routing and is used for either interacting with some API or database, like you mentioned, or for serving a new page at that URL.
As far as when you should use expressRouter vs app.get I'd say try to use the Router whenever possible as it is good practice. There's a pretty decent explanation here Difference Between app.use() and router.use() in Express
Now finally, if you want to do server side rendering with react router look here: Client Routing (using react-router) and Server-Side Routing

you need to add one non api route to serve your SPA(single page app)
create another express router and then add this
router.use('*',function(req,res,next){
var indexFile = path.resolve(__dirname,'./public/index.html');
res.sendFile(indexFile);
})
or you can just put the index.html in your public folder and load your SPA from that index page.

Related

Express doesn't load page only return json

The problem appears when after reloading a page, server return only json instead that page
I'm using React and return static files from build folder, there is also express handles routing, it is reproduced only in production mode when running localhost everything ok
app.use('/auth', authRoutes);
app.use('/user', userRoutes);
app.use(['/dota2', '/csgo', '/lol'], generalRoutes);
if (process.env.REACT_APP_ENV === 'production') {
console.log('Production is running');
app.use('/', express.static(path.join(__dirname, '../build')));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '../build', 'index.html'));
});
}
There are routes
const router = Router();
router.get('/live', liveMatches);
router.get('/upcoming', upcomingMatches);
router.get('/past', pastMatches);
router.get('/:matchId', getMatchById);
router.get('/opponents/:tournamentId', opponents);
router.post('/past-team-matches', pastTeamMatches);
You can visit mySite and you will see json as result but if you clear matchId in URL and click on any match the page will load as normal
There is also react-router
<ServiceRoute
key={key}
path={['/dota2', '/csgo', '/lol']}
exact
access
component={Matches}
/>
<ServiceRoute
key={key}
path={['/dota2/:matchId', '/csgo/:matchId', '/lol/:matchId']}
exact
access
component={MatchInfo}
/>
Let's follow the route matching that express does in this case:
When looking for /dota2/566624, it will match here: app.use(['/dota2', '/csgo', '/lol'], generalRoutes); and return the JSON.
When looking for /dota2, it won't match app.use(['/dota2', '/csgo', '/lol'], generalRoutes); so it will continue down until it matches app.get('*', (req, res) => {, serving the React page.
The problem I see here, is that you're using the very same routes for the API and the front-end routing on React. Ideally, when serving the API and the front-end application from the same server you should prefix the API routes, that way they won't clash with the front-end routes. Let's say that you prefix the API routes with: /api. Now you we have:
app.use('/api/auth', authRoutes);
app.use('/api/user', userRoutes);
app.use(['/api/dota2', '/api/csgo', '/api/lol'], generalRoutes);
// ... everything is the same down here
/api/dota2/566624. Will match against the endpoint that returns the JSON on the first load.
/dota2/566624. Will not match the JSON endpoint and will follow down to the '*' route that loads the React app, later, once the app is loaded that route will be handled by the router you're using on the react application.
Don't add the prefix as I did in the example above, use the const router = Router(); you've been using for this purpose as well. I hard-coded the prefix so that I can keep the example short.
One last question is: Why is this not happening on development?
I don't have all the information but for what I can see you're serving the front-end application from a different server than the one running the API; in that case you won't have the route clashing, since they are server from different ports, e.g front-end served on localhost:8080 and API served on localhost:5000.
I hope this helps! please comment if you need info!

In a MERN app, if you have a app.get('/') on your server and a <Route path=/' > on your client, which one will trigger first or take priority?

Say you have a React client with a nodejs express backend. On the server you have a route set up such that app.get('/') serves a Home.html. On the React side you have react-router-dom set up like
<Route path='/' component= { NotHome } />
What file will be served/shown to the user, Home or NotHome?
There is a difference between server-side routing and the client-side routing.
If you are making a standard HTTP request for the page (e.g. you type the URL in your browser's address bar), the server-side routing will take effect (e.g. serve you Home.html)
But if your Home.html then references the JS containing the <Route /> tag, client-side routing takes effect. react-router-dom will render the NotHome component in that case.
The server route will take preference, in a react app using express, your main server file should have a single route like this:
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, '/index.html'));
})
app.listen(8000, '0.0.0.0', (err) => {
if (err) {
console.log(err)
}
console.log('Listening on 8000')
})
The app.get('/*') is a catch all so that every get request e.g every address in the address bar of your browser will serve the index, which will in turn serve your bundle.js and render components based on your
Hope this helps.
Lloyd

Going from ASP.NET Web API to Node.js with Express

I'm challenged with the task to explore node.js as an alternative to ASP.NET Web API in providing a RESTful API.
I've been developing ASP.NET Web API for some time now and have got used to having certain things within that framework, I'm wondering what others are doing down the node.js route for some of these things: -
What ORM to use against MS SQL instead of Entity Framework
Is there a nice way of handling the routing similarly to what you get in Web API with the route template (routeTemplate: "api/{controller}/{id}")
I'm using Express so far and haven't found a way of applying something like this at a 'top level' so that I can have separate controllers...
That's it so far, I'm sure there are many, many more questions to come but those are my immediate concerns if anybody can help with these?
For ORM the 2 most libraries used are knexjs and sequelize, however, I prefer knex.
For the mapping part, as far as I know, there isn't a way to do it like in the c#. Usually what I do is, in the app.js load a file with my routes index. Here is an example,
In your app.js
app.use('/', require('./backend/routes/index'))
Then, in your routes/index
import express from 'express'
const router = express.Router()
// GET /
router.get('/', function (req, res) {
})
// GET /countries
router.get('/countries', (req, res, next) => {
})
// POST /subscribe
router.post('/subscribe', checkAuth, generalBodyValidation, (req, res, next) => {
})
// All routes to /admin are being solved in the backend/routes/admin/index file
router.use('/admin', require('./backend/routes/admin/index'))
module.exports = router
Your admin/index file can be
import express from 'express'
const router = express.Router()
// POST /admin/login
router.post('/login', (req, res, next) => {
})
module.exports = router
With this, you will be able to have a better structure for your routes.
Hope this asks your questions, if it does mark my answer as correct, if not tell me what you didn't understand :D

Host React and Express on the same server?

I am working on a react site that has a contact page. On the contact page there is a text field where you enter a message that will be sent to a specific email address.
Right now I'm just trying to set up express with my react app, the only thing I need Express for is this one feature.
In my react app I am doing
$.post('http://localhost:3030/API',{value:'hi'}, function(result) {
console.log(result);
});
And in my Express index.js file I'm doing
app.get('/API', (request, response) => {
console.log(request);
})
Just as a simple test to see if things are working properly.
When I run these both and attempt to execute my post function, I get the No 'Access-Control-Allow-Origin' header is present on the requested resource. error, which is basically saying that I can't make a request to a separate domain. The issue here is not that error, but the fact that I am running my Express server and react app on two different servers.
Is there a way to have them on the same server? I am very new to back-end development, any help would be very appreciated!
Yes, React runs on the client and Express is a Node.js framework. There's a pretty good chance you're using Express if you're running any boilerplate.
Here's a pretty good walkthrough on more complete routing.
https://medium.com/#patriciolpezjuri/using-create-react-app-with-react-router-express-js-8fa658bf892d
In several of my applications my routes look something like this:
//router.js--and I'm positive this is from some react-express boilerplate
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
const react = (req, res, next)=>{
res.render('react', {
title: 'React Application',
layout: false
});
};
router.get('/app', react);
router.get('/app*', react);
module.exports = router;
//app.js
...
app.use('/', routes); //<--this is the exported router.
...
If you want to be more simple it is probably something like:
let reactRoute = (request, response, next) => {
//render your react page however you're doing that.
}
express.use('/API', yourApiFunction)
express.use('/', reactRoute)
express.use('/*', reactRoute) //Wildcards are REALLY important if you're routing inside react.
You can also bypass things with a proxy but that tends to get more complex than you probably want. Also--keep in mind you don't have to stick to Node on the back-end if you're not comfortable with it. React is client side, I use it with a few production .NET apps, some PHP (lordy!), and, yes, a lot of Node servers.
to solve No 'Access-Control-Allow-Origin' header is present on the requested resource.
you've to use the cors middleware
go to the term
yarn add cors or npm i cors
in server.js
const cors = require("cors");
const express = require("express");
const app = express();
app.use(cors());

How to use AngularJS routes with Express (Node.js) when a new page is requested?

I'm using Express, which loads AngularJS from a static directory. Normally, I will request http://localhost/, in which Express serves me my index.html and all of the correct Angular files, etc. In my Angular app, I have these routes setup, which replace the content in an ng-view:
$routeProvider.when('/', {
templateUrl: '/partials/main.html',
controller: MainCtrl,
});
$routeProvider.when('/project/:projectId', {
templateUrl: '/partials/project.html',
controller: ProjectCtrl,
});
$locationProvider.html5Mode(true);
On my main page, I have a link to <a href="/project/{{project.id}}">, which will successfully load the template and direct me to http://localhost/project/3 or whatever ID I have specified. The problem is when I try to direct my browser to http://localhost/project/3 or refresh the page, the request is going to the Express/Node server, which returns Cannot GET /project/3.
How do I setup my Express routes to accommodate for this? I'm guessing it will require the use of $location in Angular (although I'd prefer to avoid the ugly ?searches and #hashes they use), but I'm clueless about how to go about setting up the Express routes to handle this.
Thanks.
with express 4, you probably want to catch all requests and redirect to angularjs index.html page.
app.use(app.router); doesn't exist anymore and res.sendfile is deprecated, use res.sendFilewith an uppercase F.
app.post('/projects/', projectController.createProject);
app.get('/projects/:id', projectController.getProject);
app.get('*', function (req, res) {
res.sendFile('/public/index.html');
});
put all your API routes before the route for every path app.get('*', function (req, res){...})
I would create a catch-all handler that runs after your regular routes that sends the necessary data.
app = express();
// your normal configuration like `app.use(express.bodyParser());` here
// ...
app.use(app.router);
app.use(function(req, res) {
// Use res.sendfile, as it streams instead of reading the file into memory.
res.sendfile(__dirname + '/public/index.html');
});
app.router is the middleware that runs all of your Express routes (like app.get and app.post); normally, Express puts this at the very end of the middleware chain automatically, but you can also add it to the chain explicitly, like we did here.
Then, if the URL isn't handled by app.router, the last middleware will send the Angular HTML view down to the client. This will happen for any URL that isn't handled by the other middleware, so your Angular app will have to handle invalid routes correctly.
I guess I should have clarified that I wasn't interested in using a template engine, but having Angular pull all of the HTML partials on it's own, Node is functioning completely as a static server here (but it won't be for the JSON API. Brian Ford shows how to do it using Jade here: http://briantford.com/blog/angular-express.html
My app is a single-page app, so I created an Express route for each possible URL pattern, and each of them does the same thing.
fs.readFile(__dirname + '/public/index.html', 'utf8', function(err, content) {
res.send(content);
});
I was assuming I would have to pass some request variables to Angular, but it looks like Angular takes care of it automatically.

Resources