Axios request from socket.io server side - node.js

I am trying to perform an axios request to the database from the socket.io server side, but am keep getting an error. How can I send Axios request or maybe there is a way to manipulate DB directly from socket.
socket.on('disconnect', reason => {
axios.get(`/api/rooms/${roomId}`)
.then(room => {
console.log(room);
socket.to(roomId).emit("disc", user)
})
.catch(err => console.log(err))
});
EDIT
So I actually ended up using mongoose query, which did the trick
Room.findOne({ _id: roomId})
.then(room => {
const filteredPlayers = room.players.filter(player => player !== user);
room.players = filteredPlayers;
room.save({players: room.players});
})

Related

Websockets with RTK Query configuration issues

I am trying to implement a Websocket connection from a React TypeScript app using RTK query. At the moment I am just trying to connect to a local socket.io server BUT ultimately it will be an AWS API Gateway with Cognito auth. In any case I having some problems getting this to work as a simple starting point. I have a few elements at play that may be causing the issue/s:-
MSW is being used to intercept http requests to mock a restful API locally. I wonder if this is one of the issues
I am adding the Websocket as a query to an RTK Query createApi object with other queries and mutations. In reality the Websocket query will need to hit a different API Gateway to the one that is being set as the baseQuery baseUrl currently. Do I need to create a new and separate RTK Query api using createApi() for the Websocket query?
Anyhow, here is the server code:-
// example CRA socket.io from https://github.com/socketio/socket.io/blob/main/examples/create-react-app-example/server.js
const getWebsocketServerMock = () => {
const io = require('socket.io')({
cors: {
origin: ['http://localhost:3000']
}
});
io.on('connection', (socket: any) => {
console.log(`connect: ${socket.id}`);
socket.on('hello!', () => {
console.log(`hello from ${socket.id}`);
});
socket.on('disconnect', () => {
console.log(`disconnect: ${socket.id}`);
});
});
io.listen(3001);
setInterval(() => {
io.emit('message', new Date().toISOString());
}, 1000);
console.log('Websocket server file initialised');
};
getWebsocketServerMock();
export {};
My RTK Query api file looks like this:-
reducerPath: 'someApi',
baseQuery: baseQueryWithReauth,
endpoints: (builder) => ({
getWebsocketResponse: builder.query<WebsocketResult, void>({
query: () => ``,
async onCacheEntryAdded(arg, { updateCachedData, cacheDataLoaded, cacheEntryRemoved }) {
try {
// wait for the initial query to resolve before proceeding
await cacheDataLoaded;
const socket = io('http://localhost:3001', {});
console.log(`socket.connected: ${socket.connected}`);
socket.on('connect', () => {
console.log('socket connected on rtk query');
});
socket.on('message', (message) => {
console.log(`received message: ${message}`);
// updateCachedData((draft) => {
// draft.push(message);
// });
});
await cacheEntryRemoved;
} catch {
// no-op in case `cacheEntryRemoved` resolves before `cacheDataLoaded`,
// in which case `cacheDataLoaded` will throw
}
}
}),
getSomeOtherQuery(.....),
getSomeOtherMutation(....),
Any advice or thoughts would be greatly appreciated! I guess my main question is should I be able to combine the websocket query in the same createApi function with other queries and mutations that need to use a different baseQuery url as they need to hit different API Gateways on AWS?
Much thanks,
Sam
You can circumvent the baseQuery from being used by specifying a queryFn instead of query on your endpoint.
In the most simple version, that just returns null as data so you can modify it later - but if you have an initial websocket request you can also do that in the queryFn.
queryFn: async () => { return { data: null } },

How to properly send a response from an express server to the client

I'm trying to fetch data from my mongoDB collection and send it back to the client in a response and for some reason the json I get as a response is always empty:
app.get("/users", bodyparser.json(), function(req, res) {
collection.find().toArray().then(dbresponse => {
console.log(dbresponse)
res.json(dbresponse);
console.log(res.json)
})
})
the dbresponse has all of the data I am looking to get, but res.json() doesn't seem to be writing anything to the response,
The client side looks like this:
fetch("/users")
.then(res => res.json)
.then(json => {
console.log(json)
Array.from(json).forEach(user => addUser(user.user, user.pass, user.id))
})
Thanks!
Client code should be fetch("/users").then(res => res.json()).
https://developer.mozilla.org/it/docs/Web/API/Fetch_API/Using_Fetch

Client side can't fetch server response

The Problem
I deployed a create-react-app webapp to aws ec2. It's used to display data from a database and send data to it. I use ExpressJS, CORS and MySQL.
With the following code i fetch the corresponding URL and the server.js sends back the database content. Until here, everything works fine.
getBets = _ => {
fetch("http://ec2***.amazonaws.com
.then(response => response.json())
.then(response => this.setState({bets: response.data}))
.catch(err => console.error(err))
};
The problem begins when sending data to the database with the following code:
addBet = _ => {
const { bet } = this.state;
fetch(`http://ec2***.amazonaws.com/bets/add?name=${bet.person_name}&bet=${bet.time_bet}`)
.then(response => response.json())
.then(this.getBets)
.catch(err => console.error(err))
};
On click the addBet-function populates the db, but in chrome I following error:
GET http://ec2***.amazonaws.com/bets/add?name=Peter%20Pan5&bet=10:17%205 net::ERR_EMPTY_RESPONSE
and
TypeError: Failed to fetch
Regarding chrome dev-tools, the first error corresponds to the fetch in the addBet function and the second error to the catch part.
On the server side I've the following code for processing the fetch:
app.get("/bets/add", (req, res) => {
const {name, bet} = req.query;
const INSERT_BET = `INSERT INTO bets (name, bet, timestamp) VALUES("${name}", "${bet}", CURTIME())`;
connection.query(INSERT_BET, (err, res) => {
if (err) {
return res.send(err);
}
else {
return res.send("succesfully added your bet");
}
})
});
I want to mention, that the res paramter in the app.get part is unused. That tells me my IDE.
After a lot of hours digging deeper in the topics of expressJS and the fetch api, I guess, that the app.get part doesn't send a response to the server. But the fetch need some response.
My Question
How do I have to change the code in the app.get part to send a proper response back to the server?
AND
Am I right with my guess?
In MYSQL when you do an insert query you get back err,results and fields in the callback function like this:
connection.query('INSERT INTO posts SET ?', {title: 'test'}, function (error,
results, fields) {
if (error) throw error;
console.log(results.insertId);
});
You have used the parameter res for result and then you have used res.send() which now corresponds to that res parameter in the callback function and not the res object.Rewrite it like this:
app.get("/bets/add", (req, res) => {
const {name, bet} = req.query;
const INSERT_BET = `INSERT INTO bets (name, bet, timestamp) VALUES(?,?,?)`;
connection.query(INSERT_BET,[name,bet,CURTIME()] ,(err, result) => {
if (err) {
return res.send(err);
}
else {
return res.send("succesfully added your bet");
}
})
});
I have also used prepared statement in place of normal sql queries. These are used to prevent sql injections. I hope it will work now.

create server with node and get endpoint with React Native

I have json file and created node.js server to set endpoint and then get this data via my React Native application. If I'm not wrong it worked correctly in friday but I had to mess something up and now I totally don't know how to fix it. All time I get error:
Possible Unhandled Promise Rejection (id: 0): TypeError: Network
request failed
self.fetch/http://192.168.1.39:8081/1c49a23b-7fbb-c640-a946-c1e001192c92:27859:18
dispatchEvent#blob:http://192.168.1.39:8081/1c49a23b-7fbb-c640-a946-c1e001192c92:29144:13
setReadyState#blob:http://192.168.1.39:8081/1c49a23b-7fbb-c640-a946-c1e001192c92:28897:15
__didCompleteResponse#blob:http://192.168.1.39:8081/1c49a23b-7fbb-c640-a946-c1e001192c92:28724:11
send/<#blob:http://192.168.1.39:8081/1c49a23b-7fbb-c640-a946-c1e001192c92:28834:18
emit#blob:http://192.168.1.39:8081/1c49a23b-7fbb-c640-a946-c1e001192c92:4538:15
__callFunction#blob:http://192.168.1.39:8081/1c49a23b-7fbb-c640-a946-c1e001192c92:2608:22
callFunctionReturnFlushedQueue/<#blob:http://192.168.1.39:8081/1c49a23b-7fbb-c640-a946-c1e001192c92:2385:11
__guard#blob:http://192.168.1.39:8081/1c49a23b-7fbb-c640-a946-c1e001192c92:2561:13
callFunctionReturnFlushedQueue#blob:http://192.168.1.39:8081/1c49a23b-7fbb-c640-a946-c1e001192c92:2384:9
onmessage#http://192.168.1.39:8081/debugger-ui/debuggerWorker.js:72:25
my Node server:
const filename = './logos.json';
const server = http.createServer((req, res) => {
if (req.url === "/logo") {
res.writeHead(200, { "Content-Type": "application/json" });
fs.createReadStream(__dirname + "/logos.json").pipe(res)
}
})
server.listen(3000, (err) => {
if (err) throw err;
console.log('server is listening on port 3000');
})
and my RN code :
syncLogoData = () => {
fetch('http://localhost:3000/logo')
.then(resp => resp.json())
.then(data => console.log(data))
.catch(err => console.log(err))
}
Looks like you're trying to run this on a device. The device doesn't know localhost points to your server. In your syncLogoData, change the uri to http://ip_address:3000/logo and it should work.
Also helpful to open http://localhost:3000/logo on your computer browser to make sure your server code is correct.

Using Node and Express, How to Call remote API from inside server.get(..)

Because of CORS problems, I want to call an external REST API from inside my node express server. That is, I have code like this that obviously does not work because it does not return.
How can I make this work and return the results of my external call?
const server = express();
server.put('/callme',(req,res) => {
axios
('http://weather.com/restapi', 'put', { zip: 10530 })
.then((resp: any) => {
console.log(' success' + resp.data);
})
.catch(function(error: any) {
console.log(error.message);
});
}
Axios returns a Promise which is resolved in the .then(). In order to get the response data back to the client you need to return it with res.send().
const server = express();
server.get('/callme', (req, res) => {
axios
.get('http://weather.com/restapi?zip=10530')
.then((resp: any) => {
res.send(resp.data);
})
.catch(function(error: any) {
console.log(error.message);
});
}
It would be a good idea to cache the weather API response for a period of time and serve the cached response for subsequent requests.

Resources