I'm trying to return some json data using the res.json() function from Express, but instead of returning a new json object each time it seems that it's appending to the old json object each time. This means that I'm receiving duplicate data in the same response object.
My code looks like this:
await Promise.all(promises)
.then(responses => res.json(responses))
.catch(error => console.error(error))
Returned data example:
[
[data]
]
Second request returned data sample:
[
[data],
[data(1)]
]
My code returns a list of responses which I want, but on repeated requests to the same function the new response is appended to the data from the old response and sent back. Is this intended? Am I doing something wrong?
edit: here is the rest of my code for context. I'm new to js and async programming so let me know if something I'm doing is terribly wrong.
const fetch = require('node-fetch')
const authFunctions = require('./auth')
var bearer_token
const space_id = 11111
let id_promises = []
async function get_category_rooms(category_id)
{
return fetch(`https://url.com/api/${category_id}`,
{
headers:
{
'Authorization': `Bearer ${bearer_token}`
}
}).then(response => response.json())
.then(data => data.map(category => category.items))
.catch(err => console.error(err))
}
async function get_category_ids() {
return fetch(`https://url.com/api/${space_id}`,
{
headers:
{
'Authorization': `Bearer ${bearer_token}`
}
})
.then(response => response.json())
.then(data =>
{
categories = data[0]["categories"].filter(category => category.name !== "category i don't want")
categories.forEach(category_item =>
{
id_promises.push(new Promise((resolve, reject) =>
{
resolve(get_category_rooms(category_item.cid))
}))
})
})
}
async function get_room_bookings(room_id) {
return fetch(`https://url.com/api/${room_id}`,
{
headers:
{
'Authorization': `Bearer ${bearer_token}`
}
})
.then(response => response.json())
.then(data => data)
}
async function get_not_group_room_reservations(req,res)
{
let room_promises = []
if (!await authFunctions.auth_check(bearer_token))
{
console.log('invalid bearer token. changing bearer')
bearer_token = await authFunctions.auth()
}
await get_category_ids()
let rooms = await Promise.all(id_promises)
.then(responses =>
{
let room_ids = responses.flat(2)
room_ids.forEach(room_id =>
{
room_promises.push(new Promise((resolve, reject) =>
{
resolve(get_room_bookings(room_id))
}))
})
})
.catch(error => console.error(error))
await Promise.all(room_promises)
.then(responses => res.json(responses))
.catch(error => console.error(error))
}
Related
I have used the shrtcode api and I dont know how to store its data.
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
fetch("https://api.shrtco.de/v2/shorten?url=www.google.com", requestOptions)//api
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
Response
ok true
result
code "fQdPc"
short_link "shrtco.de/fQdPc"
full_short_link "https://shrtco.de/fQdPc"
short_link2 "9qr.de/fQdPc"
full_short_link2 "https://9qr.de/fQdPc"
short_link3 "shiny.link/fQdPc"
full_short_link3 "https://shiny.link/fQdPc"
share_link "shrtco.de/share/fQdPc"
full_share_link "https://shrtco.de/share/fQdPc"
original_link "http://www.google.com"
How can I print or store the value of "full_short_link "?
Like this?
const doStuff = async () => {
try {
const res = await fetch('https://api.shrtco.de/v2/shorten?url=www.google.com');
const json = await res.json();
console.log('full_short_link', json.result.full_short_link);
} catch (err) {
console.error(err);
}
};
doStuff();
The below code always return the below wired object
{"_U": 0, "_V": 0, "_W": null, "_X": null}
as response.
Here is my code
getData = () => {
fetch('http://192.168.64.1:3000/getAll',{
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
})
.then((response) => {
console.log('Response:')
console.log(response.json())
console.info('=================================')
})
.catch(err => console.error(err));
}
componentDidMount(){
this.getData();
}
I am using node, express, Mysql as backend and react-native frontend
my backend code is here
app.get('/getAll',(req,res) => {
console.log('getAll method Called');
con.query('select * from dummy',(err,results,fields) => {
if(err) throw err;
console.log('Response');
console.log(results);
res.send(results);
});
});
The above code gives correct output in console but fetch API is not.
i cant find solution for the my problem. Thanks in advance.
That indicates that you are logging the promise before it resolves - the result of when you:
console.log(response.json())
How do I access promise callback value outside of the function?
As #Evert rightfully pointed out in comments, this is because response.json() returns a promise object.
So, you'll need to chain an additional .then() after you call response.json() where you log the resolved promise.
getData = () => {
fetch('http://192.168.64.1:3000/getAll',{
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(err => console.error(err));
}
Add async and await to your code:
getData = async () => {
await fetch('http://192.168.64.1:3000/getAll',{
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
})
.then((response) => {
console.log('Response:')
console.log(response.json())
console.info('=================================')
})
.catch(err => console.error(err));
}
So the issue is that you are not waiting for your Promise to resolve and this can be solved easily.
try {
const res = await fetch(
'your_api',
);
const data = await res.json();
} catch (error) {
console.log(error);
}
So the issue is that you are not waiting for your Promise to resolve. Have added await and that'll go next line once the await action is completed.
const user_fun = async (userId) => {
const response = await fetch("url");
const data = await response.json();
console.log("users ", data);
return data;
};
let data = user_fun();
console.log("users ", data);
I have to make a fetch call at a url and after getting its response I want to use those results to call another fetch. I have following code:-
async function getDate(request) {
let data;
console.log('handle request called')
await fetch('<first-url>')
.then(res => {
let urls = res.json()
console.log('urls are ', urls)
return urls.data
})
.then((urls) => {
let url = urls[0]
console.log('url is ', url)
return fetch(url)
})
.then((res) => {
data = res.body
})
.catch(() => {
console.log("something went wrong")
})
return new Response(data, {
headers: { 'content-type': 'text/html' },
})
}
I followed the above method after following this tutorial. However it does not seem to work and I am getting urls are {Promise:[Pending]}.
Here issue with return res.json(). res.json() is promisable object, so u have to resolve it to get data.
For your example:
const fetch = require("node-fetch");
async function getDate() {
let data;
console.log("handle request called");
return await fetch('<first-url>')
.then((res) => res.json())
.then((urls) => {
console.log("urls are ", urls);
if (urls.length)
return Promise.all(urls.map((url) => fetch(url).then((x) => x.json())));
return [];
})
.then((responses) => {
console.log("urls are ", responses);
return responses;
});
}
getDate().then(console.log);
Sample:
async function getDate() {
let data;
console.log("handle request called");
return await fetch("https://api.covid19api.com/countries")
.then((res) => res.json())
.then((urls) => {
console.log("urls are ", urls);
return urls;
});
}
getDate().then(console.log);
Ok, so what I am trying to do is do an axios.get() request pull specific data an id specifically, then use that id that I got to put it as a string literal so I can do my second request. I keep getting Info is not defined.
axios
.get(
`https://na1.api.riotgames.com/lol/summoner/v4/summoners/by-name/bloodstrive?api_key=${api}`
)
.then(response => {
info = response.data.id;
})
.then(
axios.get(
`https://na1.api.riotgames.com/lol/league/v4/entries/by-summoner/${info}?api_key=${api}`
)
)
.then(response => {
summoner = response.data;
return summoner;
});
let getSummonerId = (req, res) => {
res.status(200).send(summoner);
};
module.exports = {
getSummonerId
};
Fix your chaining:
axios
.get(
`https://na1.api.riotgames.com/lol/summoner/v4/summoners/by-name/bloodstrive?api_key=${api}`
)
.then(response => {
return response.data.id;
})
.then(info => {
return axios.get(
`https://na1.api.riotgames.com/lol/league/v4/entries/by-summoner/${info}?api_key=${api}`
)
})
.then(response => {
summoner = response.data;
return summoner;
});
Personally, I recommend async for tasks such as this. Makes handling things a lot easier with promises:
let fetchSummoner = async() => {
const res = await axios.get(`https://na1.api.riotgames.com/lol/summoner/v4/summoners/by-name/bloodstrive?api_key=${api}`);
const info = res.data.id;
const res2 = await axios.get(`https://na1.api.riotgames.com/lol/league/v4/entries/by-summoner/${info}?api_key=${api}`);
const summoner = res2.data;
return summoner;
}
In the current code you haven't added a return statement in the 2nd axios request. Failing to this will not fetch and return the 2nd url.
Please try the below code.
axios
.get(
`https://na1.api.riotgames.com/lol/summoner/v4/summoners/by-name/bloodstrive?api_key=${api}`
)
.then(response => {
return response.data.id;
})
.then(info => {
return axios.get(
`https://na1.api.riotgames.com/lol/league/v4/entries/by-summoner/${info}?api_key=${api}`
)
})
.then(response => {
summoner = response.data;
return summoner;
});
I am trying to test the loadAllProjects function.
The test fails at .then() with the error: TypeError: Cannot read property 'then' of undefined
I have also tried mocking the reponse of getHeadersWithToken() but could not get it to work.
Snookered on this one and would appreciate any help.
test:
it('should create SET_ALL_PROJECTS action when fetching projects', () => {
fetch
.once(JSON.stringify([{ access_token: "12345" }]))
.once(JSON.stringify({ name: "x" }))
const expectedActions = [
{ type: "SET_ALL_PROJECTS", json: { name: "x" } },
]
store.dispatch(actions.loadAllProjects.apply())
.then(() => { // FAILS HERE
expect(store.getActions()).toEqual(expectedActions)
})
});
code:
export const getHeadersWithToken = () => {
return fetch("/.auth/me", requestOptions)
.then(parseResponseAndHandleErrors)
.then(json => {
const header = 'Bearer ' + json[0].access_token
const applicationJsonHeaders = getJsonHeaders(header)
return applicationJsonHeaders
})
.catch( error=> {
console.error(error)
})
}
export const loadAllProjects = () => {
return (dispatch) => {
getHeadersWithToken()
.then(applicationJsonHeaders => {
const requestOptions = {
method: 'GET',
headers: applicationJsonHeaders,
};
return fetch(process.env.REACT_APP_PROJECTS_API_URL + "/projects", requestOptions)
.then(parseResponseAndHandleErrors)
.then(json => {
dispatch(setAllProjects(json))})
.catch(error => {
console.error(error)
dispatch(failedToLoadProjects(error))
});
})
}
}
store used in test:
const store = mockStore(Map(
{
allProjects: Map({
}),
currentProject: Map({
authenticationData: Map({
})
})
})
);
What Redux middleware are you using for the async stuff? Make sure you set up the middleware when creating the store for testing.
Since i dont see that anywhere in your code above im gonna assume we are not using that middleware here.
Since loadAllProjects is a higher order function i would do this:
it('should create SET_ALL_PROJECTS action when fetching projects', (done) => {
fetch
.once(JSON.stringify([{ access_token: "12345" }]))
.once(JSON.stringify({ name: "x" }))
const expectedActions = [
{ type: "SET_ALL_PROJECTS", json: { name: "x" } },
]
// Higher order function that returns a new function.
const loadAllProjectsAsync = actions.loadAllProjects();
// The function returned expects a dispatch from Redux as an argument.
// It will do async work and when its done, it will call the provided dispatch.
loadAllProjectsAsync(store.dispatch).then(() => {
expect(store.getActions()).toEqual(expectedActions);
done();
})
});
You also need to modify your code for loadAllProjects so that the inner function returns the promise:
export const loadAllProjects = () => {
return (dispatch) => {
// You will need to return the promise in order for the test to be able to call .then() on it.
return getHeadersWithToken()
.then(applicationJsonHeaders => {
const requestOptions = {
method: 'GET',
headers: applicationJsonHeaders,
};
return fetch(process.env.REACT_APP_PROJECTS_API_URL + "/projects", requestOptions)
.then(parseResponseAndHandleErrors)
.then(json => {
dispatch(setAllProjects(json))})
.catch(error => {
console.error(error)
dispatch(failedToLoadProjects(error))
});
})
}}
Also, as already stated, you must tell the jest when the test is done if you are testing async stuff. Do this by letting your it call take done as a param and call that as a function after you have verified the outcome i the .then()
This was just a quick fix from my side. There still might be something im missing or some bugs in the code above, but you get the point.
Let me know if you have any follow up questions?
In case this is ever useful to anyone and in acknowledgment of Septastium's answer, I eventually changed the code to:
async getHeadersWithToken(requestType) {
if (process.env.REACT_APP_RUNNING_LOCALLY==="true") {
return {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
};
}
let result = await fetch("/.auth/me", this.requestOptions)
let headers = result.json()
.then( json => {
const header = 'Bearer ' + json[0].access_token
const applicationJsonHeaders = this.getJsonHeaders(header, requestType)
return applicationJsonHeaders
})
.catch(error => {
console.error(error)
})
return headers
}
export const loadAllProjects = () => {
return async dispatch => {
const authenticator = new Authenticator()
let applicationJsonHeaders = await authenticator.getHeadersWithToken(constants.GET)
let loggedInUser = await authenticator.getLoggedInUser()
const requestOptions = {
method: 'GET',
headers: applicationJsonHeaders,
};
return await fetch(process.env.REACT_APP_PROJECTS_API_URL + "/projects", requestOptions)
.then(response => {
return parseResponseAndHandleErrors(response)
})
.then(json => dispatch(setAllProjects(json)))
.then(()=> dispatch(setAuthenticationData(loggedInUser)))
.catch(error => {
console.error(error)
return dispatch(failedToLoadProjects(error))
});
}
}
and the test to:
const checkActionsWereDispatched = async (expectedActions, actionCreator) => {
const store = mockStore(Map(
{
}),
);
store.dispatch(await actionCreator.apply()).then(() => {
expect(store.getActions()).toEqual(expectedActions)
})
}
it('should create SET_ALL_PROJECTS action when fetching projects', async () => {
fetch
.once(JSON.stringify([{ access_token: "12345" }]))
.once(JSON.stringify({ name: "x" }))
const expectedActions = [
{ type: "SET_ALL_PROJECTS", json: { name: "x" } },
]
checkActionsWereDispatched(expectedActions, actions.loadAllProjects)
});
As noted above I think Spetastium's version of the test is easier to read than mine and his article here was very helpful.