Send Map in express res.send - javascript

I'm working on a game with a friend and we need to send a Map with some stuff in it, but express only sends the user {} instead of the actual Map. The problem is at sending it and not the code itself, console.log'ging it does return the Map.
Code:
router.get("/list", async (req, res) => {
try {
const users = await userCollection.find();
accessedListEmbed(req);
let userData = new Map();
users.forEach((user) => userData.set(user.userName, user.status));
res.send(userData);
console.log(userData);
} catch (error) {
res.send("unknown");
}
});

Generally, you can only send serializable values over the network. Maps aren't serializable:
const map = new Map();
map.set('key', 'value');
console.log(JSON.stringify(map));
Either send an array of arrays that can be converted into a Map on the client side, or use another data structure, like a plain object. For example:
router.get("/list", async (req, res) => {
try {
const users = await userCollection.find();
accessedListEmbed(req);
const userDataArr = [];
users.forEach((user) => {
userDataArr.push([user.userName, user.status]);
});
res.json(userDataArr); // make sure to use .json
} catch (error) {
// send JSON in the case of an error too so it can be predictably parsed
res.json({ error: error.message });
}
});
Then on the client-side:
fetch(..)
.then(res => res.json())
.then((result) => {
if ('error' in result) {
// do something with result.error and return
}
const userDataMap = new Map(result);
// ...
Or something along those lines.

Related

How can I merge results from multiple REST endpoints?

I am new to Express.
I am creating a new API endpoint, which is getting data from two other publically available endpoints. Once I get the JSON from both APIs, I will merge them according to some rules.
let result1, result2;
// API 1
let data1;
app.get("/test1", (req, res, next) => {
axios.get("https://www.EXAMPLE.com/api/endpoint_A")
.then((response) => {
res.json(response.data)
data1 = response.data;
});
});
// API 2
let data2;
app.get("/test2", (req, res, next) => {
axios.get("https://www.EXAMPLE.com/api/endpoint_B")
.then((response) => {
res.json(response.data)
data2 = response.data;
});
});
console.log(data1); //output is undefined
console.log(data2); //output is undefined
I can see result of successful calls in both the browser and in Postman.
My problem is, that I cannot find a way to manipulate the result of each endpoint. I have tried to store like this result1 = response.data in the then but it is undefined. Once I can access the output of each response, then I have to merge them. But accessing the results outside the axios call appears to be more difficult. I don't have to use axios.
I also tried this but it didn't work.
// API 1
const data1 = app.get("/test1", (req, res, next) => {
axios.get("https://www.EXAMPLE.com/api/endpoint_A")
.then((response) => res.json(response.data));
});
console.log(data1); //output is undefined
as far as im aware data does not persist between api calls. you could combine that into a single endpoint.
//Both apis into one endpoint
app.get('/test', (req, res, next) => {
const promiseArr = [axios.get('https://www.EXAMPLE.com/api/endpoint_A'),
axios.get('https://www.EXAMPLE.com/api/endpoint_B')];
Promise.all(promiseArr).then(responses => {
const resultsFromEndpointA = responses[0];
const resultsFromEndpointB = responses[1];
//do what you want with your results here... for example..
return res.status(200).json({resultsFromEndpointA, resultsFromEndpointB});
//or do something like load them into a session
req.session.results = {resultsFromEndpointA, resultsFromEndpointB};
next();
}).catch(err => {
console.log(err);
});
};
If you are getting an array of objects with the same properties from the both endpoints, do this;
let results = [];
// API 1
app.get("/test1", (req, res, next) => {
axios
.get(
"https://www.EXAMPLE.com/api/endpoint_A"
)
.then((response) => {
results.push(response.data);
});
});
// API 2
app.get("/test2", (req, res, next) => {
axios
.get(
"https://www.EXAMPLE.com/api/endpoint_B"
)
.then((response) => {
results.push(response.data);
});
});

How can i parse this result from a fetch call EXpress NoseJs Javascript

Here is the code of my script, it's in the index.html file, I know it's wrong to be there but first I'm trying to make it work, then I'll move it.
readOperaciones();
async function readOperaciones(){
try{
const listaOr = document.getElementById('listaOrdenada');
const result = await fetch("http://localhost:8080/operaciones", {method: "GET"})
const operaciones = await JSON.parse(result)
//operaciones.forEach(t=>{
for (var i = 0; i < operaciones.length; i++) {
var row = operaciones[i];
console.log(row.codeemp);
}
/*tt = JSON.stringify(t);
const li = document.createElement("li");
li.textContent = tt.text;*/
/*t.forEach(cell=>{
const li = document.createElement("li")
li.textContent = cell.text;
li.id = cell.id;
})*/
//})
}
catch(e){
console.log("Error al leer las operaciones descriptas")
}
}
Here is the connecting with express
const {Client} = require('pg');
const express = require ("express")
const app = express();
app.use(express.json())
const client = new Client({
user: "postgres",
password: "1234",
host: "localhost",
port: 5432,
database: "webaduana",
})
app.get("/", (req, res) => res.sendFile(`${__dirname}/index.html`))
app.get("/operaciones", async (req, res) => {
const rows = await readAll();
res.setHeader("content-type", "application/json")
res.send(JSON.stringify(rows))
})
async function readAll(){
try{
const results = await client.query("select * from operaciones")
return results.rows;
}
catch(e){
console.log(e)
return [];
}
}
I don't know if I need to put more information but my question about all this code is here
I've tried many ways of doing it but I can't get those results in an ol element.
It doesn't give me any error, it just doesn't print anything in the HTML page
Add a .then to the fetch chain and print your results:
fetch('http://example.com/movies.json')
.then(response => {
console.log('response: ' + JSON.stringify(response));
})
...
...
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
you can use .json() method :
const fetched = await fetch("/url", {
method: 'GET',
});
const fetchedJson: object = await fetched.json();
console.log(fetchedJson)
There are a few ways to do that.
Using Promises
The fetch response object inherently includes some methods that can help you to get a response in different forms such as .json(), .text(), and .status. Learn more about it here. So, if you simply want to parse the answer into a JSON object, you can do
function doSomethingOnParsedJson(res) {
// Do something on the response here...
}
function readOperacions() {
fetch("http://localhost:8080/operaciones", {
method: "GET",
})
.then(res => res.json())
.then(doSomethingOnParsedJson) // Pass in a function without parentheses
.catch(console.error);
}
It's cleaner if you define a separate function which performs the job you want to do on the parsed response and pass the function (without parentheses) to then but you can also go ahead and give it a function directly like:
function readOperacions() {
fetch("http://localhost:8080/operaciones", {
method: "GET",
})
.then(res => res.json())
.then(parsedResponse => {
// do something...
})
.catch(console.error);
}
Using Async/Await
You can also use the async/await feature to achieve that.
function doSomethingOnParsedJson(res) {
// Do something on the response here...
}
async function readOperacions() {
try {
// Get the response from the server.
const res = await fetch("http://localhost:8080/operaciones", {
method: "GET",
});
// Parse it into a JSON object.
const parsedJson = res.json();
// Do something on it.
doSomethingOnParsedJson(parsedJson);
} catch (error) {
// Show an error if something unexpected happened.
}
}
Side Note
There is a neater way to send a JSON response in Express. You can use the .json method on the Express response object.
app.get("/operaciones", async (req, res) => {
const rows = await readAll();
/* Don't do this!
res.setHeader("content-type", "application/json")
res.send(JSON.stringify(rows))
*/
/* Do this instead ;-) */
res.json(rows);
})
Voila! It's that simple.

GET request from a local server not working

I am trying to obtain json files with axios' GET request, but the information is not retrieved.
In index.js (retrieving information):
axios.get('http://localhost:1000/getpost/')
.then((response) => {
console.log(response);
});
Backend endpoint getpost.js (sending information):
var router = require('express').Router();
var Posts = require('../models/post-model.js');
router.route('/').get(() => {
Posts.find({color: "Green"})
.then((res) => {
return res;
});
});
module.exports = router;
I have also tried return Posts.find({color: "Green"}); inside the router.route('/').get... function,
but the value returned is different compared to the one in the promise which is the one I need. I checked that the information is actually sent with console.log(res), but it is not received in the frontend--when I log the result there, it is null.
You are not doing anything with the route response. Maybe something like...
router.route('/').get((req, res1) => {
Posts.find({color: "Green"})
.then((res) => {
res1.end(res);
});
});
(assuming res is the data in plaint text, if it is a JavaScript object you'll do res1.json(res) or res1.jsonp(res))
You need to map the route to getpost as:
router.route('/getpost')
So your getpost would be as:
var router = require('express').Router();
var Posts = require('../models/post-model.js');
router.route('/getpost').get(() => {
Posts.find({color: "Green"})
.then((res) => {
res.send({status:200,message:res});
});
});
module.exports = router;
Apparently, I was not passing the result properly.
The router in getpost.js should be:
router.route('/').get((req, res) => {
Posts.find({color: "Green"})
.then((posts) => res.json(posts));
});

Google Cloud Functions - access to key's value

I'm trying to return a value out of an array of values I get from querying Datastore.
results[0] have this content: {"prod_name":"Muffin","prod_price":3.99}.
I'd like to return via res.send only: 3.99
I've tried results[0].prod_price, or results[0]['prod_price'], I have tried saving results[0] as variable and trying to return prod_price, but nothing works.
Any help is appreciated.
My code is here:
const Datastore = require('#google-cloud/datastore');
const Storage = require('#google-cloud/storage');
// Instantiates a client
const datastore = Datastore();
const storage = new Storage();
exports.getprice = function getprice (req, res) {
const kind = datastore.createQuery("Dialogflow");
const filter = kind.filter("prod_name", req.body.queryResult.parameters['bakery_items']);
return query = datastore.runQuery(kind)
.then( (results) => {
const entities = results[0];
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ "fulfillmentText": entities}));
})
.catch((err) => {
console.error(err);
res.status(500).send(err);
return Promise.reject(err);
});
};
I got it.
Actually I kept results instead of forcing results[0], and realized the output had an extra array, so to access the value, I had to do: results[0][0]['prod_price']
Thanks to JavaScript console.

Koa/Node.js - Use multiple models within one controller function

I am attempting to create a new 'Vault' from a Post Request from my frontend (built in React) using Mongoose Schema.
When I hit the create button in my app, the Post Request initiates, but returns:
POST http://localhost:3000/vaults/create 500 (Internal Server Error)
When my controller function createVault() is initiated, it will successfully create a 'Vault' from the model (see below):
//Create a vault
module.exports.createVault = async (ctx, next) => {
if ('POST' != ctx.method) return await next();
try {
if (!ctx.request.body.name) {
ctx.status = 404
}
//Create new vault
const vault = await Vault.create({
name: ctx.request.body.name,
url: ctx.request.body.url,
description: ctx.request.body.description
});
await vault.save();
//Return vault
ctx.body = vault;
ctx.status = 201;
}
catch (error) {
if (error) {
console.log('Error in the createVault controller:', error);
ctx.status = error.response.status;
ctx.body = error.response.data;
}
}
}
However, my problem occurs when I try to add a second Schema model; I am attempting to create a 'Crypt' from each of the items in the ctx.request.body.crypts array (see below):
//Create a vault
module.exports.createVault = async (ctx, next) => {
if ('POST' != ctx.method) return await next();
try {
if (!ctx.request.body.name) {
ctx.status = 404
}
//Create new vault
const vault = await Vault.create({
name: ctx.request.body.name,
url: ctx.request.body.url,
description: ctx.request.body.description
});
//Create new crypts
const promises = await ctx.request.body.crypts.map(crypt => Crypt.create({
name: crypt
}));
//Add reference to vault
const crypts = await Promise.all(promises);
vault.crypts = crypts.map(crypt => crypt._id);
await vault.save();
//Return vault and crypts
ctx.body = [vault, crypts];
ctx.status = 201;
}
catch (error) {
if (error) {
console.log('Error in the createVault controller:', error);
ctx.status = error.response.status;
ctx.body = error.response.data;
}
}
};
The error I receive say I cannot map over an undefined object, although I am using const crypts = await Promise.all(promises);
Can anyone suggest a correct way around this problem? Many thanks.
I managed to fix my problem by creating a function called cleanBody(body) which manually parsed the data for me to use.
I logged typeof ctx.request.body which returned a string and revealed my problem. The cleanBody(body) function just check if the body was an object, then used JSON.parse() if it was a string (see below):
const cleanBody = body => {
return typeof body !== 'object' ? JSON.parse(body) : body;
};
My mistake was assuming APIs from Postman and APIs called in the app would pass the same data, even when everything looks the same

Categories