Refactoring how react/node handles response - javascript

I'm using a react frontend and fetching data from my node server. I feel like my code looks a bit redundant, is there a better way to refactor all this?
App.js
searchStock = async (value) => {
let priceURL = `/stock/${ value }/price`
// fetch price data
fetch(priceURL)
.then(res => {
if (res.ok) {
res.json()
.then( (result) => {
this.setState({
price: result
})
})
}
else {
console.log("Something went wrong...")
}
})
}
server.js
app.get('/stock/:symbol/price', (req, res) => {
const token = 'abcde123'
const symbol = req.params.symbol
const apiURL = `https://sandbox.iexapis.com/stable/stock/${symbol}/price?token=T${token}`
fetch(apiURL)
.then(response => {
console.log(response.status)
if (response.ok) {
response.json().then((data) => {
res.json(data)
});
}
else {
res.sendStatus(response.status)
}
})
.catch(error => {
console.log(error);
});
})

As these two code segments live in different apps (frontend and backend) I don't think there's a pretty way of DRYing this.

Introduce library file with fetching logic
src/helper.js
exports.fetchHelper = (url) => fetch(url)
.then(response => {
if (response.ok) {
return response.json();
} else {
res.sendStatus(response.status)
}
})
.catch(console.error);
and use respectively
app.js
import { fetchHelper } from 'src/helper'; // or whatever else your bundler setup requires
searchStock = async (value) => {
const priceURL = `/stock/${ value }/price`;
await fetchHelper(priceURL).then((result) => {
this.setState({
price: result
})
})
}
server.js
const fetchHelper = require('src/helper').fetchHelper;
app.get('/stock/:symbol/price', (req, res) => {
const token = 'abcde123'
const symbol = req.params.symbol
const apiURL = `https://sandbox.iexapis.com/stable/stock/${symbol}/price?token=T${token}`
fetchHelper(apiURL).then((response) => {
res.json(data);
})
Or something similar...

Related

Data not returning from service to context when using promises

I'm getting some data from server and have set-up this service on client to request them accordingly:
const serviceSyncFollowedArtists = async userId => {
if (!userId) return
const { data } = await axios.get(`${httpLink}/sync`, {
params: {
accessToken,
userId,
},
})
return data
}
service is called within context:
const syncFollowedArtists = async () => {
await spotifyService
.serviceSyncFollowedArtists(user.userId)
.then(res => {
if (res.length === 0) return
dispatch({
type: 'SYNC',
data: res,
})
})
.catch(err => {
console.log(err)
})
}
It works fine as I want it to, however, before, I have set up the service to request data using promises:
const serviceSyncFollowedArtists = async userId => {
if (!userId) return
await axios
.get(`${httpLink}/sync`, {
params: {
accessToken,
userId,
},
})
.then(res => {
return res.data
})
.catch(err => {
console.log(err.message)
})
}
Even though I manage to obtain the data from server inside the service, when it's returned to the function in context, it's empty, undefined. Is threre any reason for this?
You are getting undefined because you are not returning anything from the function in the case of promises, unlike you are doing it in the first case
So just add a return keyword
const serviceSyncFollowedArtists = async userId => {
if (!userId) return
return await axios
.get(`${httpLink}/sync`, {
params: {
accessToken,
userId,
},
})
.then(res => {
return res.data
})
.catch(err => {
console.log(err.message)
})
}

Uncaught (in promise) Error: Network Error at createError

I'm going to use Axios to communicate API.
But that kind of error keeps coming out. I don't understand this problem. I searched on the Internet and tried everything. Help me.
All I want is to click on that button to see the low value in the developer tool.
useEffect(() => {
setJwt(getClientCookieFromClient('jwt'));
}, []);
const customFetch = async () => {
const res = await axios
.get(`${process.env.NEXT_PUBLIC_WECODE_URI}/subscription/master_table`, {
headers: {
Authentication: jwt,
},
})
.then((res) => res.data);
if (!res.data.success) {
alert(res.data.message);
}
};
...
<button onClick={() => customFetch()}>API호출버튼</button>
Alway wrap await inside try/catch block.
const customFetch = async () => {
try {
const res = await axios
.get(`${process.env.NEXT_PUBLIC_WECODE_URI}/subscription/master_table`, {
headers: {
Authentication: jwt,
},
})
.then((res) => res.data);
if (!res.data.success) {
alert(res.data.message);
}
} catch (error) {
console.log(error);
// Do something with error
}
};
Try
useEffect(() => {
setJwt(getClientCookieFromClient('jwt'));
}, []);
const customFetch = async () => {
const res = await axios.get(`${process.env.NEXT_PUBLIC_WECODE_URI}/subscription/master_table`, {
headers: {
Authentication: jwt,
},
});
if (!res.data.success) {
alert(res.data.message);
}
};
Note:
not sure about you response structure. Current code works as expected for structure:
res = { data: { data: {success: true}}}
if it is not so, then use if statement as !res.success
useEffect(() => {
setJwt(getClientCookieFromClient('jwt'));
}, []);
const customFetch = async () => {
const res = await axios
.get(`${process.env.NEXT_PUBLIC_WECODE_URI}/subscription/master_table`, {
headers: {
Authentication: jwt,
},
})
.then((res) => res.data)
.catch((err) => console.log("Error while fetching",err)); //<--- use .catch for catching error
if (!res.data.success) {
alert(res.data.message);
}
};

How can I "encapsulate" this code into a module so it could become reusable?

I have got this Node.JS snippet and would like to write it as a module, so I can use recaptcha in different parts of my system.
This is how it currently looks like:
app.post('/register_user', (req, res) => {
const secret_key = process.env.RECAPTCHA_SECRET;
const token = req.body.recaptcha;
const url = `https://www.google.com/recaptcha/api/siteverify?secret=${secret_key}&response=${token}`;
fetch(url, { method: "post",})
.then((response) => response.json())
.then((google_response) => {
if (google_response.success == true) {
res.format({'text/html': () => res.redirect(303, '/register'),})
} else {
return res.send({ response: "Failed" });
}
})
.catch((error) => {
return res.json({ error });
});
})
I have tried to write the following module which works absolutely great, but I have absolute no idea about how to call it from the app.post, since I always get undefined as return:
import fetch from 'node-fetch';
export function fetch_out(url, timeout = 7000) {
return Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('timeout')), timeout)
)
]);
}
export async function checkRecaptcha(token, secret_key){
const url = "https://www.google.com/recaptcha/api/siteverify?secret=" + secret_key + "&response=" + token;
try{
const response = await fetch_out(url, 1000);
const google_response = await response.json();
}catch(error){
return error;
}
return google_response;
}
Any help would be appreciated! Thanks!
You could make this method reusable by removing the framework actions that need to happen and only return if the validation was successful or not. This way, it will be reusable in another project that doesn't use a specific framework.
Example module;
export async function checkRecaptcha(token, secret_key) {
const url = `https://www.google.com/recaptcha/api/siteverify?secret=${secret_key}&response=${token}`;
const response = await fetch(url, { method: "post",});
if (!response.ok) return false;
const json = await response.json();
if (!json.success) return false;
return true;
}
Usage:
import { checkRecaptcha } from "./some-file-name";
app.post('/register_user', async (req, res) => {
const isHuman = await checkRecaptcha(req.body.recaptcha, process.env.RECAPTCHA_SECRET);
if (!isHuman) {
return res.send({ response: "Failed" });
}
return res.format({'text/html': () => res.redirect(303, '/register'),});
});
If you specifically want to call an action after the validation, you can also use successful and error callbacks.

JS read file onload returns undefined

I want to read a TXT file from a directory, I have this code which works fine
window.onload = () => {
fetch("file.txt")
.then(res => res.text())
.then(data => {
console.log(data);
});
};
But I want to exe the fetch call in a function like so:
window.onload = () => {
const filePath = "file.txt";
const fileData = readDataFile(filePath);
console.log(fileData);
};
const readDataFile = path => {
fetch(path)
.then(res => res.text())
.then(data => {
return data;
});
};
But in this case, it returns undefined.
Another problem with it, is I can't catch if an error occurs, I tried adding catch to the promise and throw an error but it does not work. This is what I've tried:
window.onload = () => {
fetch("file.txt")
.then(res => res.text())
.then(data => {
console.log(data);
})
.catch(err => {
throw new Error("ERROR!");
});
};
THANKS :)
This works:
const readDataFile = async path => {
try {
const response = await fetch(path);
const data = await response.text();
return data;
} catch (err) {
console.log('Cannot read file.');
}
}
window.onload = async () => {
const filePath = 'data.txt';
const fileData = await readDataFile(filePath);
console.log(fileData);
}
But again, the catch method does not work ? am I doing it wrong ?

having trouble chaining multiple axios request

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;
});

Categories