what is the correct way to use NodeJs with React?
Currently what I am doing is running Node on port 3000 and React on port 3001
Now, I my Node I have this route
app.get("/", (req, res) => {
console.log(req.user)
res.json(req.user)
})
Here console.log shows user details when I manually go to localhost:3000 but If I make an axios request from my react to the above given url it shows undefined.
componentWillMount() {
axios.get("http://localhost:3000/").then(response => {
console.log(response)
}).catch(error => {
console.log(error)
})
}
Now, The req.user is something which were getting from passport google Stratergy and I since the log from localhost:3000 shows the data and the log from localhost:3001 does not show data.
I am confused if I am using the node correct way? i.e sending in request via axios and getting data via res.json
Also, since most of the tutorial or the tutorial I followed used EJS instead of React where user mostly did res.render
I just wanted to know the equivalence of res.render for react in NodeJS
[Update:] I am enabling cross origin resource sharing via plugin in google chrome
EDIT: In discussion with OP I found out that this is most likely a passport authentication middleware related issue. Original answer follows.
Looks like a CORS issue, as your frontend providing server is on port 3001, and backend on 3000. I can show you the way I'm using it (in react+node CORS setup, although the issue has nothing to do with React) and I have no CORS issues:
On frontend I use native browser's fetch:
const fetchRelative = async (path, options) => {
const url = new URL('http://localhost:3000/' + path);
return await ((await fetch(url, options)).json());
};
Here async/await syntax is used. I'm using babel for transpile, but maybe browsers support that natively.
Options provided to fetch are for example:
{
method: 'POST',
body: JSON.stringify(order),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
};
For a simple get request you can leave the options parameter empty.
On backend (node+koa server) I use this:
const Koa = require('koa');
const koaBody = require('koa-body');
const cors = require('koa-cors');
const startServer = (port) => {
const server = new Koa();
server.use(cors({ origin: '*', allowMethods: ['GET', 'POST', 'DELETE', 'PUT', 'OPTIONS'] }));
server.use(koaBody());
server.use(bindRoutes());
server.listen(port);
};
Basically the same is for express server (https://expressjs.com/en/resources/middleware/cors.html).
bindRoutes is just koa-router configuration extracted in a separate file:
const Router = require('koa-router');
const bindRoutes = () => {
const router = new Router();
router.get('restaurants', async (ctx) => {
ctx.body = 'abc;
});
return router.routes();
};
CORS plugin is not used here.
P.S.
async/await explaination and Browser support status
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
fetch explaination and Browser support status
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
You can run both your Node server and React app on different ports and proxy the React app back to your Node server. This can be done without a CORS plugin. More details on how to set this up is here: https://medium.freecodecamp.org/how-to-make-create-react-app-work-with-a-node-backend-api-7c5c48acb1b0
Related
I am building a small website using LiveScore api from rapidapi.com. How can I hide my api key when deploying my application. Tried .env method, serverless methods but didn't do much help. I am trying the api hiding method for the first time. Maybe that's why I am not getting it. Is there any method to hide api key which is fairly simple but a decent hiding?
//index.js
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Key': 'xxxxxxxxxx',
'X-RapidAPI-Host': 'livescore6.p.rapidapi.com'
}
};
fetch('https://livescore6.p.rapidapi.com/matches/v2/list-by-date?
Category=soccer&Date=20231801&Timezone=-7', options)
.then(
response => {
response.json().then(
data => {
//my code here
})
In plain client side Javascript there is not much you can do to hide API Keys. I took a quick glance at the RapidAPI docs and also this blog post from them, but they just use the API Keys as-is without securing anything. (lol)
So if you're worried about that information leaking, I would recommend you to create a backend in any backend language you prefer (it could be NodeJS, if you want to use Javascript) and use it as a proxy to make a request to that LiveScore API. If you do this you don't have to hardcode the API Keys in your client code, you could use dotenv in your backend, also you could control which endpoints to use and even add some custom basic authentication to be able to make a request.
This is a basic example using NodeJS and express:
const express = require('express');
const fetch = require('node-fetch');
const cors = require('cors');
const app = express();
app.use(express.json());
app.use(cors());
app.get('/api/livescore', async (req, res) => {
try {
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Key': process.env.RAPID_API_KEY,
'X-RapidAPI-Host': process.env.RAPID_API_HOST
}
};
const rapidApiResponse = await fetch('https://some-rapid-api-endpoint.com', options);
const parsedResponse = await rapidApiResponse.json();
return res.json({ data: parsedResponse });
} catch (err) {
return res.status(500).json({ err: err.message });
}
});
app.listen(process.env.PORT || 3000);
I have a Vue 3 website showing a list fetched from a REST-API (using the fetch method).
Then sometimes this list is modified in the original DB and I would like to update my vue component accordingly.
The good news is that a webhook is posted to me by the DB service when an entry is modified.
However, I do not know how to consume this webhook in my Vue project.
I know how to consume it with an express server with something like
app.post("/hook", (req, res) => {
console.log(req.body)
}
but I don't see how to connect this with my Vue app ?
Maybe it's not even a good approach.
--- Update:
I have implemented #kissu solution (SSE version) but I still have an issue.
I have an Express server running :
```js
const app = express();
```
and i wait for a webhook:
app.post("/hook", (req, res) => {
x=req.body.my_item;
newUpdate = true;
res.status(200).end()
})
and I have a get route for the SSE
app.get('/events', async function(req, res) {
const headers = {
'Content-Type': 'text/event-stream',
'Connection': 'keep-alive',
'Cache-Control': 'no-cache',
'Access-Control-Allow-Credentials' : false,
'Access-Control-Allow-Origin': 'https://grange.vercel.app',
};
res.writeHead(200, headers);
while (true) {
await new Promise(resolve => setTimeout(resolve, 500));
if (newUpdate)
{
res.write(`data: ${x}\n\n`);
res.send(`data: ${x}\n\n`);
newUpdate = false;
}
}
});
and await app.listen(443);
On the Vue side I have
sseClient = this.$sse.create({
format: 'plain',
polyfill: true,
url: 'https://sse.mydomain.fr/events',
withCredentials: false,
});
sseClient.connect()
.catch((err) => console.error('Failed make initial connection:', err));
sseClient.on('', this.handleMessage)
and handleMessage do the job of updating my page.
It works for a while then after a minute of inactivity (or sometimes randomly) I receive an 404 error from the sseserver (on the Vue page) because "Access-Control-Allow-Origin is missing".
It looks like somehow, my Vue app cannot grab the header of the SSE sometimes and then fail.
Any suggestion #kissu ?
A client-side app cannot react to a webhook per se.
You will need some kind of polling or socket communication like:
long polling
server sent events
websockets
I have a vue app which calls the backend through express. When I add an image to a request the request is not redirected to the backend. However, when I call the backend directly from the vue app, without express, the request is handeled correctly. The image gets lost somehow on the way.
Vue-code:
uploadImage(){
this.loadingImage = true
const url = "/person/"+localStorage.getItem("userUuid")+"/picture";
var config = {headers: {"Authorization": "Bearer "+localStorage.getItem("token")}};
const fd = new FormData();
fd.append('image', this.picture, this.picture.name)
this.$http.post(url, fd, config)
.then((response) => {
console.log(response)
this.loadingImage = false
//window.location.reload()
})
.catch((error) => {
console.log(error)
})
app.js
const proxy = require('express-http-proxy');
const express = require('express')
const fileUpload = require('express-fileupload');
const app = express();
app.post('/person/:id/picture', proxy(config.backendURL, {
filter: function(req, res) {return checkBearer(req, res)}
}));
Currently what you are attempting to do is locate the images in the public folder, as browsers assume that /<path> using the same host and port. In your case, you are using express so your API/Webserver is on a different host and or port. With your current configuration, you would have to have your images hosted in the /public directory in vue for it to work as expected.
Therefore you need to tell your browser to look elsewhere for the image. Since it is on the same domain (localhost) and is on a different port you can use a computed property to return the current hostname. Assuming you are on your local machine it would be localhost or we can get the domain dynamically through window.location.hostname.
In Vue add a computed property to get your domain/hostname and change the port number like so:
computed:{
baseUri(){
return `${window.location.hostname}:3000`;
}
}
Then modify your URL to include the hostname we got from our computed property
const url = `${this.baseUri}/person/${localStorage.getItem("userUuid")}/picture`;
Now your images should load from the correct server
You can also add some logic to your computed property, let's say your image URLs are hosted on a different domain in production, but when you are developing locally they are running from express on your local server.
computed:{
baseUri(){
return process.env.NODE_ENV === 'development' ?
`${window.location.hostname}:3000`:
'myimages.mydomain.com'; // <-- you can also change the port here if you need
}
}
I' trying to deploy an Vue app which has a separate backend and which will be hosted in different domain. For example:
meow.cat.xyz (App)
api.meow.cat.xyz (API)
Now after npm run build I tried to preview it locally by running serve -s dist and the application is severing at localhost:5000. However the problem is it not sending API request at the current end point (which is localhost:8000 at local and api.meow.cat.xyz at server). I tried config CORS as following
vue.config.js
module.exports = {
devServer: {
port: process.env.VUE_APP_DEV_PORT,
proxy: process.env.VUE_APP_API_ROOT_PATH,
},
};
.env.development
VUE_APP_API_ROOT_PATH = 'http://localhost:8000/api'
VUE_APP_DEV_PORT = 3000
Note that I'm using axiox. Here is my axios setup.
API.js
import axios from "axios";
const injectAccessToken = (config) => {
const accessToken = localStorage.getItem("access_token");
if (accessToken)
config.headers.common["Authorization"] = `Bearer ${accessToken}`;
return config;
};
const config = {
baseURL: process.env.VUE_APP_API_ROOT_PATH,
};
const API = axios.create(config);
API.interceptors.request.use(injectAccessToken);
export default API;
and Using it as following
Login.vue
import API from "#/api/Api";
<script>
const res= await API.post('login')
</script>
This solution is not working yet. Its sending request at http://localhost:5000. What's the point ? Note that I'm using axios. thanks in advance.
Allow CORS requests from the server
With the Access-Control-Allow-Origin header, you can specify what origins can use your API.
app.get('/api', (req, res) => {
res.set('Access-Control-Allow-Origin', 'http://localhost:3000');
res.send({
api: "your request."
});
})
Allow CORS from the app's origin on the server (api).
This has nothing to do with with the client (app)
I have one Javascript file linked to HTML and that js file is calculating an array on clicking submit button in Html and I want to get that data to node js file on post route without displaying it in HTML page. How should I do that?
Your nodeJS program is running on a server, which could just be your computer if you are using localhost, which means that it is in not connected to your HTML page. Therefore, you need to send the data from your js file via fetch request. In your nodeJS file, you need a route for receiving that data, which you create using express.
const express = require("express");
const {json} = require("body-parser");
const app = express();
app.post("/submitData", (req, res) => {
const data = req.body;
console.log(data);
res.status(200).json({"Message": "Data posted", data});
})
app.listen(3000,() => {
console.log("Server running on port 3000");
})
Now, in your javascript file, you need a fetch request.
fetch(http://localhost:3000/submitData, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
}).then(response => {
return response.json();
}).then(data => {
console.log(data)
})
This should do the trick. I would also suggest you download Postman, which is great for testing APIs and trying out http requests
I forgot to point out, after doing:
const app = express();
you should put:
app.use(json());
I apologise for the mistake, it should remove the error you mentioned in the comment.