How to connect to MongoDB server and npm start at the same time for MERN app - node.js

I am making a MERN app and I notice that every time I want it to work, I have to first connect to the MongoDB server by "node server.js".
Then, I have to do "npm start" to run the react app which is connected to the server I just connected to.
Is there a way to do both of these actions using one command?

If you are using this for production, then you could use nodemon, which is a good tool that hot reloads your server and front end.
"scripts": {
"dev": "SET THIS=development & nodemon server.js",
},
Also, make sure you're server JS has a catch all that points to your app, such as:
server.get('*', (req, res) => {
return handle(req, res)
})
backend
- - server.js //with mongodb connection, and api routes.
//This is what you are going to use for your API calls from the front end. i.e http://backend.com/userapi/
frontend
- - server.js that contains the catch all statment. Also would add custom routes in here i.e
server.get('/posts/:id', (req, res) => {
return app.render(req, res, '/article', { id: req.params.id })
})

Related

cannot post ; post can't be made with axis on react

I am trying to make a post request in React to the server
my React app is running at port 3000 & express app is running at port 9000
React:
axios.post("/").then((response)=>{
console.log(response.data)
}).catch((e)=>{
console.log(e.response.data)
this.out = e.response.data
})
Express:
app.post("/", (req, res) => {
console.clear()
console.log(req.body)
res.end("req")
})
on the web console it says :
"Failed to load resource: the server responded with a status of 404 (Not Found)"
on the app 'postman' It runs just fine
I tried to follow this YT tutorial https://www.youtube.com/watch?v=kJA9rDX7azM
First you need to check weather you add a proxy in your React APP project Package.Json file under the private dependency name,
proxy:
'http://localhost:9000/'
Axios first look for the port you are requesting for in the current server which is in you case is / so / is also a port in frontend so it never goes for the backend be safe to go with
axios.post("http://localhost:9000/")
.then((response)=>{
console.log(response.data)
})
.catch((e)=>{
console.log(e.response.data)
})
Secondly make sure you must install the axios dependency in your react project
Seems like you forgot to add domain in the axios request.
axios.post("http://localhost:9000/").then((response)=>{
console.log(response.data)
}).catch((e)=>{
console.log(e.response.data)
this.out = e.response.data
})

express app is not sending index.html file to client

So my express app has a small Node server setup so it can serve up the index.html file when the home route '/' is hit. This is a requirement of using the App Services from Azure, there has to be this server.js file to tell the server how to serve up the client, and i had a previous implementation of this working, however i wanted to change my file structure. previously i had, the client React app in a folder client and the server.js in a folder server along with all of the conrtollers and routes. i've since moved the server API to its own application as there are other apps that depend on it. and i moved the client up one directory into the main directory. Everything was working fine till the other day when all of the sudden when you hit the home route / it will not serve up the index.html file. if you hit any other route it works, if you even hit a button linking back to the homepage, it works, but it wont serve up the app from the / and i cannot for the life of me figure out why, on my development server there are no errors in the console. and im most definitely targeting the correct directory and place for the index. but its like the server isnt reading the route to serve up.
if (process.env.NODE_ENV === 'production') {
console.log('running');
app.use(express.static(path.resolve(path.join(__dirname, 'build'))));
// no matter what route is hit, send the index.html file
app.get('*', (req, res) => {
res.sendFile(path.resolve(path.join(__dirname, 'build', 'index.html')));
});
} else {
app.get('/', (req, res) => {
res.send('API is running...');
});
}
So here im saying if the NODE_ENV is in production make the build folder static, and then whatever route is hit. (Note: i also tried this app.get with other route formats such as /* or / all have the same issues. however in my previous iteration when the client and server where deployed in the same location, /* is what i used.) The .env varialbes are setup correctly, as when the server is ran, itll console log running.. but even if i put a console log inside of the app.get() its like its never hit unless i access the route from something else first.
for example, if i place a console log inside of app.get that states hit whenever the route is hit, hitting / directly does nothing, but if i go to /login itll serve up the correct html on the client and console log hit in the terminal...
If you are having server files inside the client react app, then we are basically accessing file which are not inside our server file. So, we can serve static files using the following code:
const express = require("express");
const app = express(); // create express app
const path = require('path');
app.use(express.static(path.join(__dirname, "..", "build")));
app.use(express.static("build"));
app.listen(5000, () => {
console.log("server started on port 5000");
});
Now in your packages.json of the client react app change the name of start tag under scripts tag to start-client. Then add this following tag to the scripts tag:
"start":"npm run build && (cd server && npm start)",
Basically, this will build the react app and start the server.
It should look like this :
Also in the packages.json of your server add the following tag under script tag
"start":"node server.js"
So when you run the following command npm start it should look like this :

My CRUD app works locally but not on Heroku

I've created a CRUD app and it works locally, but I can't get it to work fine on heroku. It deploys correctly, the website seems to work, but then I can't get the items I need from the database, as it keeps saying connection refused.
I added the .env variables to Heroku, as well as setting the port to process.env.PORT || 5000 and app.listen(port), I'm not sure what's causing the error. I also have a Procfile with web: node server.js, and a "start" script in package.json that points to server.js. It seems that the server doesn't start at all.
Here the repo in case you want to have a look https://github.com/ThomYorke7/inventory, here the app on heroku https://boardgamenerd.herokuapp.com/
The problem lies in the fact that your application has a backend (server) and a frontend (client) which are served differently locally than on Heroku.
I suppose locally your client is running on localhost:3000 (as it is the default with create-react-app you bootstrapped).
While your backend is running on localhost:5000, your client's package.json contains this line to make it work locally:
"proxy": "http://localhost:5000",
If I visit this page of your app: https://boardgamenerd.herokuapp.com/ > boardgames,
then I face these errors on the browser console:
boardgames-list.jsx:18
Error: Network Error
at e.exports (createError.js:16)
at XMLHttpRequest.p.onerror (xhr.js:83)
xhr.js:178
GET http://localhost:5000/boardgames/ net::ERR_CONNECTION_REFUSED
It tells you that your production version still calls backend on localhost:5000.
I.) First I'd try to fix these fetches by changing to relative URLs.
E.g. the above example (boardgames-list.jsx:18)
❌ your current script has hardcoded localhost fetch at the moment:
useEffect(() => {
axios
.get('http://localhost:5000/boardgames/')
.then((response) => {
setBoardgames(response.data);
setLoading(false);
})
.catch((err) => console.log(err));
}, []);
✔️ make it relative to root by removing "http://localhost:5000":
useEffect(() => {
axios
.get('/boardgames/')
.then((response) => {
setBoardgames(response.data);
setLoading(false);
})
.catch((err) => console.log(err));
}, []);
And it will work on Heroku. In case it wouldn't: see my suggestion below.
II.) Second, a suggestion:
Now your https://boardgamenerd.herokuapp.com/boardgames route uses the following backend endpoint to fetch data: https://boardgamenerd.herokuapp.com/boardgames/
The difference is only the last slash ("/") character which can be confusing and cause more issues later!
It is a best practice to add a differentiator path element to your backend endpoints, like /api/. For example: https://boardgamenerd.herokuapp.com/api/boardgames So you can be sure by first sight which GET request related to the backend and which one to the client.
If you'd go with this solution, you will need to add the following to your server.js:
app.use(express.static(path.join(__dirname, 'client', 'build')))
// required to serve SPA on heroku production without routing problems; it will skip only 'api' calls
if (process.env.NODE_ENV === 'production') {
app.get(/^((?!(api)).)*$/, (req, res) => {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'))
})
}
/^((?!(api)).)*$/ regex skips URLs containing "api" in their path, so they won't be served static as the client/build folder's content - api calls won't be served from static and will work fine.

React Native unable to run a successful fetch to express API

Given the following setup:
server.js
const express = require('express')
const path = require('path')
const app = express()
const cors = require('cors')
const port = process.env.PORT || 8080
app.use(cors())
app.get('/api', (req, res) => {
res.send({code: 200, message: 'I have arrived!'})
})
app.listen(port, () => console.log(`I can hear your thoughts on ${port}`))
and the presentational component with call:
App.js
componentDidMount() {
fetch(`/api`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then(res => {
console.log(res)
return res.json()
}).then(response => {
console.log(response)
this.data = response
}).catch(error => {
this.error = error.message || error.error
})
}
package.json:
"scripts": {
"start": "npm-run-all --parallel start:client start:server",
"start:client": "node node_modules/react-native/local-cli/cli.js start",
"start:server": "node server.js",
"test": "jest"
},
I am running the app via yarn start, and I see the log: "I can hear your thoughts"... The fetch call, however, is never made. If I supply another fully qualified url within the fetch call it returns the data as expected, however I am unable to hit the express api from within the component.
If I place http://localhost:8080/api in the browser I get the response.
If I place http://localhost:8080/api in the fetch call it is never called (or at least doesn't appear to be).
How can I properly configure this to call the express api when running locally?
As always any and all direction is appreciated, so thanks in advance!
I believe the issue for this is two fold.
Firstly you are running the server and the bundler in the same terminal window. I believe that this is causing them to get confused.
Run them in separate windows. Yes that means you have to run an extra command but it will mean that you will be able to clearly see the logs for each of them.
Also you may have to restart you bundler, especially when you add new packages which will mean restarting your server.
Similarly when you update your server you will have to restart it also causing you to restart your bundler. It doesn't seem like a good idea running them in the same window.
Secondly you are using the localhost for the api. This works nicely on your computer because the api is running on your computer's localhost so it can find it. However, when you run it on a device and you use localhost it looks for the api on your device's localhost and cannot find it there, thus it doesn't bring back a result.
Your solution is quite clear. Firstly, run your bundler and your server in different terminal windows. And secondly use the ip address of your computer so that the emulator/simulator can easily find where the api is located.
I copied your code and made only two changes to the react-native code.
Added alerts to show the response and error from the fetch request
Used my local ip address of my computer rather than localhost
Here are some images of me running it on both Android and iOS, using your code and the changes that I detailed above.
Android
iOS

AngularJs route reaload fails in nodeJs

I managed to get an example app working following several examples, but theres a problem i cant seem to solve. In the angular app routes work ok like this:
- http://localhost:8888/#/login works
but when i reload the url i get the Cannot GET /login error from nodeJs.
i tried doing this:
app.get('/*', function (req, response) {
response.write(__dirname + '/../Client/index.html');
response.end();
});
and this
app.get('/login', function (req, response) {
console.log('*****************************************');
response.sendfile(path.resolve(__dirname + '/../Client/'));
});
but none work, i always get the same error and in the first one it just writes the url.
I think the problem is that while in the app angular knows the routing and handle the reloads because the file is served with
app.use('/', express.static(__dirname + '/../Client/'));
but when the url doesnt have the angular hashtag nodejs tries to look for the url but fails. is there a way i fix this? maybe redirecting to the correct url or something, i searched for hours trying stuff but none worked, thanks for taking your time.
The error is generated from the fact that Angular will rewrite the window.location at runtime while you are using your application starting from the root localhost/ and routing you to localhost/login (without calling the server with a GET).
So, when you refresh, the browser didn't know that the url was written by javascript, so he calls the node server that reject the request.
I other word: you need to start your navigation always from the root.. but this is unusable.
So I figure out how to develop a single project with Angular (4 in my case) for the front-end and nodejs-express for the back-and.
I've tested this solution for redirect with fragment from different source like auth0 and the use of JSON Web Token.
This let me to deploy this application easily to a single heroku instance.
NodeJs Configuration
The first middlewere have to be the path where the Angular's app is build
app.use(express.static(__dirname + './dist'));
Then I have configured express-jwt (the regular expression is for all the url that not starts with "/api")
app.use(expressJwt({secret: appConfig.SecurityJwt}).unless({
path: [
'/api/v1/login',
/^(?!\/api).*/gm
]
}));
Then the business logic of front end:
app.post('/api/v1/login', ...
app.get('/api/v1/myOtherServices' ....
And in the very end of routing configuration, even after the custom error handler:
app.use(appHandleError);
app.get('*', function (req, res) {
res.sendFile('index.html', {root: './dist'});
});
app.listen(4200);
Angular routing
I did not do anything particular here:
const routes: Routes = [
{path: 'home', component: LoginComponent},
{path: 'authenticated', component: ActivatePageComponent},
{path: '', redirectTo: '/home', pathMatch: 'full'}
];
#NgModule({
imports: [RouterModule.forRoot(routes, {useHash: false, enableTracing: false})],
exports: [RouterModule]
})
export class AppRoutingModule {
}
Then in the package.json I have made a custom script:
"scripts": {
"ng": "ng",
"start": "node server.js",
"build": "ng b --prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"postinstall": "ng b --prod",
"buildAndStart": "ng build && npm start",
"i18n": "ng-xi18n --i18nFormat=xlf"
},
That I can launch with the command npm run buildAndStart so the angular project is builded and the server node is up and running.
My angular app will be listening to http://localhost:4200/ and all the rest service at the /api/* path as well.
So, for example, url like:
http://localhost:4200/authenticated#access_token=123
http://localhost:4200/authenticated?access_token=123
will be evaluated by Angular, and Angular can call all the /api/v1/myOtherServices without any problem, even the refresh/reload will not generate any error this time.

Resources