I want to retrieve data from a API call and send the results to the user in NodeJS. There are separate functions for the API call and for the route call. The data is print to the console within the API call function, but not been sent to the route call. Please be kind to help me up with this. The API needs Basic auth headers.
import express from 'express';
import bodyParser from'body-parser';
import fetch from 'node-fetch';
// This server is used to get the issues of the project and store them in an array
/* App config */
const app = express()
const port = process.env.PORT || 9000;
/* Middleware */
app.use(bodyParser.json())
var issues = []
var issueIds = []
async function getIssueIds()
{
try
{
const response = await fetch('API link',
{
method: 'GET',
headers:
{
'Authorization': `Basic ${Buffer.from(
'authorization data'
).toString('base64')}`,
'Accept': 'application/json',
}
})
.then(res => res.json())
.then(json => {
issues = json.issues;
for(let i = 0; i < issues.length; i++)
{
issueIds.push(issues[i].id)
}
return issueIds;
})
.then(function(data) {
return data;
})
.catch(err => console.error(err));
}
catch(err)
{
return err;
}
}
app.get('/api/issues', (req, res) =>
{
getIssueIds().then(issues => {
console.log("Issue array: "+ issues);
});
res.set('Access-Control-Allow-Origin', '*');
//If success, send the data
res.status(200).send(issueIds);
});
/* Listen */
app.listen(port, () => console.log(`Listening on port : ${port}`));
Related
This is the front-end code which is used for sending access token to server site.
useEffect(() => {
const getProducts = async () => {
try {
const url = `http://localhost:5000/product?email=${user.email}`
const { data } = await axios.get(url, {
headers: {
authorization: localStorage.getItem('accessToken')
}
});
setProducts(data);
} catch (err) {
const status = err.response.status;
if (status === 401 || status === 403) {
signOut(auth);
navigate('/login');
localStorage.removeItem('accessToken')
toast.error(err.response?.data?.message);
}
}
}
getProducts();
}, [user.email]);
This is server site express code for response. Why every time it is receiving two request and sending two response?
app.get('/product', verifyToken, async (req, res) => {
const decoded = req.decoded?.email;
const queryEmail = req.query?.email;
if (decoded === queryEmail) {
const query = { email: queryEmail };
const cursor = medicineCollection.find(query);
const products = await cursor.toArray();
res.send(products);
} else {
res.status(403).send({ message: "Forbidden Access" })
}
})
Maybe you take user.email in a state which is updating somehow so that's why useEffect is calling again and giving you twice response.
I have been working on this issue for 2 days, looked at various pages and cannot find a single solution that would work.
Please only reply if you know how to write them with async await functions and please reply if you know the answer of fetch api. I am not looking for axios solutions for the time being.
I have a backend server which runs on port 8000 of localhost, frontend runs on port 3000. Front end is written in React, backend is written in Node/Express.
I am able to successfully make a GET request from backend server but the POST request fails for some reason with the error "VM942:1 POST http://localhost:8000/frontend-to-backend 500 (Internal Server Error)"
Backend server has this error: SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse ()
// React-To-Node-Connection
// React "App.js" file
// "package.json" file contains this
// "proxy": "http://localhost:8000"
useEffect(() => {
const getBackend = async () => {
const res = await fetch('backend-to-frontend');
const data = await res.json();
if (!res.ok) {
throw new Error(`Cannot get data from backend server. HTTP Status: ${res.status}`);
}
console.log(data.message);
// Prints "Hi from backend!"
}
getBackend();
const postBackend = async () => {
try {
const res = await fetch('http://localhost:8000/frontend-to-backend',
{
method: 'POST',
mode: 'no-cors',
body: JSON.stringify({ message: 'Hi from frontend!' }),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}
);
if (res.ok) {
const data = await res.json();
console.log(data);
}
} catch (error) {
console.error(error);
}
}
postBackend();
}, []);
Now the backend code:
app.get('/backend-to-frontend', (req, res) => {
res.json({ message: 'Hi from backend!' });
});
app.post('/frontend-to-backend', (req, res) => {
try {
const reactMessage = JSON.parse(req.body.data);
console.log(`message: ${reactMessage}`);
} catch (err) {
console.error(err);
}
});
How to fix this? Please help!
Full backend server code can be found here:
const express = require("express");
const app = express();
app.use(express.urlencoded({ extended: true }));
app.get('/backend-to-frontend', (req, res) => {
res.json({ message: 'Hi from backend!' });
});
app.post('/frontend-to-backend', (req, res) => {
try {
const reactMessage = JSON.parse(req.body.data);
console.log(`message: ${reactMessage}`);
} catch (err) {
console.error(err);
}
});
const port = process.env.PORT || 8000;
app.listen(port, function () {
console.log(`Backend server started on port ${port}.`);
});
with no-cors, you can only use simple headers, so you cannot POST JSON (see: Supplying request options)
Try urlencoded:
const postBackend = async() => {
try {
const res = await fetch('http://localhost:8000/frontend-to-backend', {
method: 'POST',
mode: 'no-cors',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
'message': 'Hi from frontend!'
})
});
if (res.ok) {
const data = await res.json();
console.log(data);
}
} catch (error) {
console.error(error);
}
}
postBackend();
and on the server, don't parse req.body, as it's already done by middleware:
app.post('/frontend-to-backend', (req, res) => {
console.log('req.body: ', req.body);
try {
const reactMessage = req.body.message;
req.body.data may be an object (check with debugger). If so, you might try to stringify before parsing :
JSON.parse(JSON.stringify(req.body.data))
I finally found the answer, here is my sample code. I did not change the React code that much so it is pretty much same, I removed the no cors section and added cors to Express JS code.
Here is my React code.
// React-To-Node-Connection
// "package.json" file has the following line
// "proxy": "http://localhost:8000"
// React Code
useEffect(() => {
const getBackend = async () => {
const res = await fetch('/backend-to-frontend');
const data = await res.json();
if (!res.ok) {
throw new Error(`Cannot get data from backend server. HTTP Status: ${res.status}`);
}
console.log(data.message);
}
getBackend();
const postBackend = async () => {
try {
await fetch('http://localhost:8000/frontend-to-backend',
{
method: 'POST',
body: JSON.stringify({ message: 'Hi from frontend!' }),
headers: {
'Content-Type': 'application/json'
}
}
);
} catch (err) {
console.error(err);
}
}
postBackend();
}, []);
And here is my Express JS code.
const express = require("express");
const app = express();
app.use(express.urlencoded({ extended: true }));
// Express JS Code
const cors = require('cors');
app.use(express.json());
app.use(cors());
app.get('/backend-to-frontend', (req, res) => {
res.json({ message: 'Hi from backend!' });
});
app.post('/frontend-to-backend', (req, res) => {
try {
console.log(req.body.message);
} catch (err) {
console.error(err);
}
});
const port = process.env.PORT || 8000;
app.listen(port, function () {
console.log(`Backend server started on port ${port}.`);
});
Thanks.
In the nodeJs application, I'm downloading a file with Axios. when the client cancels the request I have to stop downloading. After starting downloading How can I stop downloading?
with the following code, I notice that the client cancel its request:
req.on('close', function (err){
// Here I want to stop downloading
});
complete code :
const express = require('express')
const app = express()
const Axios = require('axios')
app.get('/download', (req, res) => {
req.on('close', function (err){
// Here I want to stop downloading
});
downloadFile(res)
})
async function downloadFile(res) {
const url = 'https://static.videezy.com/system/resources/previews/000/000/161/original/Volume2.mp4'
console.log('Connecting …')
const { data, headers } = await Axios({
url,
method: 'GET',
responseType: 'stream'
})
const totalLength = headers['content-length']
let offset = 0
res.set({
"Content-Disposition": 'attachment; filename="filename.mp4"',
"Content-Type": "application/octet-stream",
"Content-Length": totalLength,
// "Range": `bytes=${offset}` // my problem is here ....
});
data.on('data', (chunk) => {
res.write(chunk)
})
data.on('close', function () {
res.end('success')
})
data.on('error', function () {
res.send('something went wrong ....')
})
}
Axios documentation has a section about cancelation.
The code would look like:
// before sending the request
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
// then pass-in the token with request config object
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
});
// upon cancelation
source.cancel('Operation canceled by the user');
Moreover, looks like there's an open issue for supporting AbortController/AbortSignal in Node.js 15+. You can check it out here.
How to use fastify-redis plugin from other controllers or other.js while declaring the redis connection in server.js
server.js
const fastify = require('fastify')({ logger: false })
const routes = require('./routes')
fastify.register(require('fastify-redis'), { host: '127.0.0.1' })
routes.forEach((route, index) => {
fastify.route(route)
})
const start = async () => {
try {
await fastify.listen(3000)
fastify.log.info(`server listening on ${fastify.server.address().port}`)
//const { redis } = fastify
//console.log(redis)
} catch (err) {
fastify.log.error(err)
process.exit(1)
}
}
start()
Controller -> books.js
exports.getBooks = async (request, reply) => {
//console.log(redis)
let data = {
book: 'Book 1',
author: 'Author 1'
}
//return data
return redis.get('key1') // Not Defined
//return redis.get('key1')
}
So, simply how can I use the Redis instance in other files to set some values in Redis as a to implement caching database data.
If you write your handler with a simple function (aka no arrow function), the this object will be binded to the fastify server:
exports.getBooks = async function (request, reply) {
console.log(this)
let data = {
book: 'Book 1',
author: 'Author 1'
}
return this.redis.get('key1')
}
i would do something like this: basically passing app instance over to the exported function in route that are used to bootstrap routes.
in route
module.exports = fastify => [
{
url: '/hello',
method: 'GET',
handler: async (request, reply) => {
const { redis } = fastify
// ...
}
},
{
url: '/hello',
method: 'POST',
handler: async (request, reply) => {
const { redis } = fastify
// ...
}
}
]
and bootstraping routes at start
app.register(plugin1)
.register(plugin2)
.after(() => {
// bootstraping routes
// route definition should either be done as a plugin or within .after() callback
glob.sync(`${__dirname}/routes/*.js`, { cwd: __dirname })
.map(f => path.resolve(__dirname, f))
.forEach(file => {
const routeConfigs = require(file)(app)
for (let i = 0; i < routeConfigs.length; i += 1) {
const routeConfig = routeConfigs[i]
app.route(routeConfig)
}
})
})
Send instances of fastify to decorateRequest when calling .after () then you will be able to use redis when calling request in the route handler.
I want to perform a realtime crud using vuex, node, express and socketio but using the following syntax I can't get the result.
Server
index.js
const server = app.listen('3000',() => {
console.log('<--- Web Server Starter --->')
const io = require('./sockets')(server)
io.on('connection', socket=>{
console.log('client connected');
})
})
socket.js
let io
module.exports = {
init:httpServer =>{
io = require('socket.io')(httpServer)
return io
},
getIo:()=>{
if(!io){
throw new Error('socket io not initialized')
}
return io
}
}
user.js
const io = require('../socket')
router.post('/newuser',(req, res) => {
res.json({ serverResponse: 'userCreated' })
io.getIo().emit('newuser',{serverResponse:'created',user:user})
})
Client
Module user.js (VUEX actions)
getusers({ commit }){
const sessionToken = localStorage.getItem('sessionToken')
axios.get('/newuser', {
headers: {
Authorization: `Bearer ${localStorage.getItem('sessionToken')}`
},
})
.then(response => {
const socket = openSocket('http://localhost:3000')
socket.on('newuser', data => {
if (data.serverResponse === 'created') {
this.users = data.user
commit('GET_USERS', users)
})
})
.catch(error => {
alert(error)
})
})
When I create the new user, the user list is not updated automatically, but I have to refresh the page to see the new user, why does this happen?
This is because in your backend you are handling the post url-endpoint '/newuser' to get the data. You are not actually posting the data using socketio, therefore if you don't update the page, your axios.get function isn't going to have any new data to get until the API you are posting to has refreshed. It would be better to put your socket client code outside of the axios promise so that the data is primarily updated on the client by socketio and not by the API.
EDIT:
This is the code for it in your client
getusers({
commit
}) {
const sessionToken = localStorage.getItem('sessionToken')
axios.get('/newuser', {
headers: {
Authorization: `Bearer ${localStorage.getItem('sessionToken')}`
},
})
.then(response => {
console.log('success');
})
.catch(error => {
alert(error)
})
const socket = openSocket('http://localhost:3000')
socket.on('newuser', data => {
if (data.serverResponse === 'created') {
this.users = data.user
commit('GET_USERS', users)
})
})
You had a problem with your .catch part of the promise as it was inside the .then part and I also moved your socket code outside of the promise.
So in your server when you post to /newuser. you send emit from the socketio
on your client you dont need to use axios to check if some socket events has been fired, try to remove the axios.get() and keep
const socket = openSocket('http://localhost:3000')
socket.on('newuser', data => {
//do some thing
})