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
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 express app, running on port 8000, I also have react on port 3000.
I am trying to implement google oauth.
This is what I did.
I try to send get request to my api endpoint,
then my express server redirect user to google Sign in.
And then, how can I send token from server to client from get request?
Here's my express code.
I try to send cookies directly from the server,
but I don't know why the cookies is not available on port 3000 which is my react app.
Is there any neat way to send jwt to client?
router.get(
"/google/callback",
passport.authenticate("google", {
scope: ["profile", "email"],
failureRedirect: "/login",
session: false,
}),
(req, res) => {
const payload = {
id: req.user.id,
};
jwt.sign(payload, secret, { expiresIn: tokenLife }, (err, token) => {
if(err) {
console.log('error', err)
}
const jwt = `Bearer ${token}`;
console.log('ini token', token)
const htmlWithEmbeddedJWT = `
<html>
<script>
// Save JWT to cookie
// document.cookie = 'token=${jwt};'
document.cookie = 'token=${jwt}; SameSite=None; Secure'
// Redirect browser to root of application
window.open('http://localhost:3000/login', '_self')
</script>
</html>
`;
res.send(htmlWithEmbeddedJWT);
});
}
);
It is not available because you have responded to the google call and then redirected the page on a client to the localhost apparently cookies will not be available.
The common way to handle auth in such cases is to define a success redirect that will expect to receive somekind of a token in query params.
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.
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
little help?
I am trying to write pure JSON to a file inside my project, my project tree looks like this:
src
->app
-->components
--->people.component.ts
--->(other irrelevant components)
-->services
--->people.service.ts
-->data
--->JSON.json
->(other irrelevant src files)
The code in my people.component.ts is just used to call and subscribe to a function inside my people.service.ts, passing the newPerson property which is data-binded from the DOM using angular2 magic; this is the function inside name.service.ts:
public addPerson(newPerson) {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post('app/data/PEOPLE.json', newPerson, { header: headers })
.map(res => res.json())
}
My objective is to write (if necessary replace) the newPerson property (or the entire file) inside PEOPLE.json. of course, the current addPerson() function returns an error.
I've also tried the put method, it errors slightly differently, but i haven't found solutions to either method.
I know categorically it's not an error with the format/type of data i'm trying to put in PEOPLE.json file.
Unfortunately, you can not PUT or POST directly to a file on your local filesystem using client side (browser) JavaScript.
Consider building a simple server to handle a POST request. If you are most comfortable with JavaScript, try Express with Node.js
// server.js
'use strict'
const bodyParser = require('body-parser');
const express = require('express');
const fs = require('fs');
const app = express()
app.use(bodyParser.json());
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:8000');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.header('Access-Control-Allow-Methods', 'POST');
next();
});
app.post('/', (req, res) => {
console.log('Received request');
fs.writeFile('json.json', JSON.stringify(req.body), (err) => {
if (err) throw err;
console.log('File written to JSON.json');
res.send('File written to JSON.json')
})
});
app.listen(3000, ()=>{
console.log('Listening on port 3000. Post a file to http://localhost:3000 to save to /JSON.json');
});
You cannot write to files from Browser. Period. Even if such action is possible it will be stored on User side, not your server. If your task is indeed to write something on user end, please refer to localStorage documentation (or couple other API implementations). But if you are going to user that file for some purpose outside of your browser, it will be non-trivial task.
If you want to save file on server, then you need to hande it on back end.