Is there a better way to write this part of the code? It works, but the eslint is complaining that
'resp' is already declared in the upper scope
In this part
return parseJSON(resp).then((resp) => {
throw resp
})
This is the entire code
componentDidMount = async () => {
const parseJSON = (resp) => (resp.json ? resp.json() : resp)
const checkStatus = (resp) => {
if (resp.status >= 200 && resp.status < 300) {
return resp
}
return parseJSON(resp).then((resp) => {
throw resp
})
}
const headers = {
'Content-Type': 'application/json'
}
try {
const data = await fetch('http://myurl/api', {
method: 'GET',
headers: headers
}).then(checkStatus)
.then(parseJSON)
this.setState({ data })
} catch (error) {
this.setState({ error })
}
}
You have variable name resp in twice in the same scope on below lines:
const checkStatus = (resp) => {
and return parseJSON(resp).then((resp) => {.
change one of resp.
Related
I have two functions that using axios post information to different APIs I created with node and express. Both of them have an interceptor as I get a response from by backend with messages, errors, and other information. Yet when I post the to the second url ("/users/login") the first interceptor still fires off (in the addUser instead of the findUser function) even though it is not in the same function. How do I fix this?
async function addUser(user) {
const config = {
headers: {
"Content-Type": "application/json",
},
};
try {
const interceptorResponse = axios.interceptors.response.use(
(response) => {
if (typeof response.data === "object") {
let success = response.data.registerSuccess;
let errors = response.data.errors;
let data = response.data.data;
let message = response.data.message;
setData(() => {
return { ...data, errors, registerSuccess: success, message };
});
}
return response;
}
);
await axios.post("/users/register", user, config);
axios.interceptors.request.eject(interceptorResponse);
} catch (err) {}
}
async function findUser(user) {
const config = {
headers: {
"Content-Type": "application/json",
},
};
try {
axios.interceptors.response.use((response) => {
console.log(response);
if (typeof response.data === "object") {
let loginSuccess = response.data.data.loginSuccess;
let message = response.data.message;
console.log(response.data);
setData(() => {
return { ...data, loginSuccess, message };
});
}
return response;
});
await axios.post("/users/login", user, config);
} catch (error) {}
}
I'm doing requests to my API server to authenticate a user, that's not the problem. The problem is that I don't know why my async function doesn't return anything, and I get an error because the data that I want from this function is undefined.
Don't worry if the error management is ugly and in general I can do this better, I'll do that after fixing this problem.
Utils.js class
async Auth(username, password) {
const body = {
username: username,
password: password
};
let req_uuid = '';
await this.setupUUID()
.then((uuid) => {
req_uuid = uuid;
})
.catch((e) => {
console.error(e);
});
let jwtData = {
"req_uuid": req_uuid,
"origin": "launcher",
"scope": "ec_auth"
};
console.log(req_uuid);
let jwtToken = jwt.sign(jwtData, 'lulz');
await fetch('http://api.myapi.cc/authenticate', {
method: 'POST',
headers: { "Content-Type": "application/json", "identify": jwtToken },
body: JSON.stringify(body),
})
.then((res) => {
// console.log(res);
// If the status is OK (200) get the json data of the response containing the token and return it
if (res.status == 200) {
res.json()
.then((data) => {
return Promise.resolve(data);
});
// If the response status is 401 return an error containing the error code and message
} else if (res.status == 401) {
res.json()
.then((data) => {
console.log(data.message);
});
throw ({ code: 401, msg: 'Wrong username or password' });
// If the response status is 400 (Bad Request) display unknown error message (this sould never happen)
} else if (res.status == 400) {
throw ({ code: 400, msg: 'Unknown error, contact support for help. \nError code: 400' });
}
})
// If there's an error with the fetch request itself then display a dialog box with the error message
.catch((error) => {
// If it's a "normal" error, so it has a code, don't put inside a new error object
if(error.code) {
return Promise.reject(error);
} else {
return Promise.reject({ code: 'critical', msg: error });
}
});
}
Main.js file
utils.Auth('user123', 'admin')
.then((res) => {
console.log(res); // undefined
});
Your Async function must return the last promise:
return fetch('http://api.myapi.cc/authenticate', ...);
or await the result and return it:
var x = await fetch('http://api.myapi.cc/authenticate', ...);
// do something with x and...
return x;
Notice that you don’t need to mix promise syntax (.then) with await. You can, but you don’t need to, and probably shouldn’t.
These two functions do exactly the same thing:
function a() {
return functionReturningPromise().then(function (result) {
return result + 1;
});
}
async function b() {
return (await functionReturningPromise()) + 1;
}
await is not to be used with then.
let data = await this.setupUUID();
or
let data=null;
setupUUID().then(res=> data = res)
I would try something like this:
const postReq = async (jwtToken) => {
const body = {
username: username,
password: password,
};
try {
const res = await fetch('http://api.myapi.cc/authenticate', {
method: 'POST',
headers: { "Content-Type": "application/json", "identify": jwtToken },
body: JSON.stringify(body),
})
if (res) {
if (res.status == 200) {
return res.json();
} else if (res.status == 401) {
const data = res.json();
console.log(data.message)
throw ({ code: 401, msg: 'Wrong username or password' });
} else if (res.status == 400) {
throw ({ code: 400, msg: 'Unknown error, contact support for help. \nError code: 400' });
}
}
} catch (err) {
console.error(err)
}
};
const Auth = async (username, password) => {
const jwtData = {
"origin": "launcher",
"scope": "ec_auth"
};
try {
const req_uuid = await this.setupUUID();
if (req_uuid) {
jwtData["req_uuid"] = req_uuid;
const jwtToken = jwt.sign(jwtData, 'lulz');
return await postReq(jwtToken);
}
} catch (err) {
console.error(err);
};
}
I am looping the array using bluebird map method and then using each row as a payload to my apicall function. Everything works perfectly but I want to incorporate timeout method when response from the api takes more than 10 seconds and also settimeout method to delay 2 seconds after each api call. Please let me know how can I acheive this. I am fine without using bluebird. Thanks in advance.
handleSubmit = () => {
Promise.map(this.props.data, row => {
return apiCall(api, row).then((response) => {
if(response){
console.log(response)
} else{
console.log("failed")
}
})
}, { concurrency: 1 } )
}
apiCall: (api, input ) => {
switch (process.env.NODE_ENV) {
case 'production': { // Production environment
return new Promise((resolve) => {
window.runApi(api, input, (response) => {
if (typeof response === 'string') {
const jsonResponse = JSON.parse(response);
resolve(jsonResponse);
} else {
resolve(response);
}
});
});
}
default: {
const requestBody = input;
if (input !== "") {
requestBody.username = "user";
requestBody.password = "password";
}
const requestUrl = `api`;
return fetch(requestUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestBody),
})
.then(res => res.json());
}
}
}
I'm getting the following error:
TypeError: Converting circular structure to JSON
at JSON.stringify (<anonymous>)
at stringify (/usr/local/lib/node_modules/firebase-tools/node_modules/express/lib/response.js:1123:12)
at ServerResponse.json (/usr/local/lib/node_modules/firebase-tools/node_modules/express/lib/response.js:260:14)
at cors (/Users/landing-page-backend/functions/zohoCrmHook.js:45:43)
at process._tickCallback (internal/process/next_tick.js:68:7)
for the HTTP response in my createLead function, despite the fact that the function is executed properly and does what it's supposed to do (which is to create an entry in my CRM).
I've pointed out in the following code where the error occurs:
const axios = require('axios');
const functions = require('firebase-functions');
const cors = require('cors')({ origin: true })
const clientId = functions.config().zoho.client_id;
const clientSecret = functions.config().zoho.client_secret;
const refreshToken = functions.config().zoho.refresh_token;
const baseURL = 'https://accounts.zoho.com';
module.exports = (req, res) => {
cors(req, res, async () => {
const newLead = {
'data': [
{
'Email': String(req.body.email),
'Last_Name': String(req.body.lastName),
'First_Name': String(req.body.firstName),
}
],
'trigger': [
'approval',
'workflow',
'blueprint'
]
};
const { data } = await getAccessToken();
const accessToken = data.access_token;
const leads = await getLeads(accessToken);
const result = checkLeads(leads.data.data, newLead.data[0].Email);
if (result.length < 1) {
try {
return res.json(await createLead(accessToken, newLead)); // this is where the error occurs
} catch (e) {
console.log(e);
}
} else {
return res.json({ message: 'Lead already in CRM' })
}
})
}
function getAccessToken () {
const url = `https://accounts.zoho.com/oauth/v2/token?refresh_token=${refreshToken}&client_id=${clientId}&client_secret=${clientSecret}&grant_type=refresh_token`;
return new Promise((resolve, reject) => {
axios.post(url)
.then((response) => {
return resolve(response);
})
.catch(e => console.log("getAccessToken error", e))
});
}
function getLeads(token) {
const url = 'https://www.zohoapis.com/crm/v2/Leads';
return new Promise((resolve, reject) => {
axios.get(url, {
headers: {
'Authorization': `Zoho-oauthtoken ${token}`
}
})
.then((response) => {
return resolve(response);
})
.catch(e => console.log("getLeads error", e))
})
}
function createLead(token, lead) {
const url = 'https://www.zohoapis.com/crm/v2/Leads';
return new Promise((resolve, reject) => {
const data = JSON.stringify(lead);
axios.post(url, data, {
headers: {
'Authorization': `Zoho-oauthtoken ${token}`
}
})
.then((response) => {
console.log("response in createLead", response)
return resolve(response);
})
.catch(e => reject(e))
})
}
function checkLeads(leads, currentLead) {
return leads.filter(lead => lead.Email === currentLead)
}
Console.logging all the parameters indicate that the they are not the issue. The configuration of the Zoho API is, also, not the issue considering the fact that the entries are being properly made into the CRM. My assumption is that it would have to do with the HTTP response in the JSON format.
You're trying to convert a promise to JSON, not going to work. Your createLead function returns a promise, not a JSON. The promise is the 'circular object'.
I have a function that I call using
fetch(http://localhost:8888/.netlify/functions/token-hider?
stateName=' +stateName)
on my client side.
the token-hider function looks like this:
const qs = require("qs");
const fetch = require("node-fetch");
var alertEndpoint = "";
var parkEndpoint = "";
var parksWithAlerts = "";
exports.handler = async function getURLS(event, context, callback)
{
// Get env var values defined in our Netlify site UI
const {api_key, alert_api_url, park_api_url} = process.env;
var stateName =event.queryStringParameters.stateName;
alertEndpoint = `${alert_api_url}${stateName}${api_key}`;
parkEndpoint = `${park_api_url}${stateName}${api_key}`;
getData();
async function getData(alertsArea, alertHeader) {
const [getAlertData, getParkData] = await
Promise.all([fetch(alertEndpoint), fetch(parkEndpoint)] );
var alertResults = await getAlertData.json();
var parkResults= await getParkData.json();
var alertData = alertResults.data;
var parkData = parkResults.data;
parksWithAlerts = parkData.map(park => {
park.alertData = alertData.filter(alert => alert.parkCode ===
park.parkCode);
return park
});
console.log(parksWithAlerts);
}
console.log(callback);
};
how could I return the contents of parksWithAlerts back to the client side after this function is finished?
Try to learn more about callback functions in Javascript.
It is right there in your code, the callback that you are printing is actually suppose to be called after you have executed your code and you can do like this callback(parksWithAlerts);.
While calling the function getURLS you will provide the function which is suppose to get called with args.
Examples : https://www.geeksforgeeks.org/javascript-callbacks/
Here is an example with error handling and returning a response type of JSON
token-hider
import fetch from "node-fetch";
// Get env var values defined in our Netlify site UI
const {api_key, alert_api_url, park_api_url} = process.env;
async function getJson(response) {
return await response.json();
}
const alertEndpoint = stateName => {
return new Promise(function(resolve, reject) {
fetch(`${alert_api_url}${stateName}${api_key}`)
.then(response => {
if (!response.ok) { // NOT res.status >= 200 && res.status < 300
return reject({ statusCode: response.status, body: response.statusText });
}
return resolve(getJson(response))
})
.catch(err => {
console.log('alertEndpoint invocation error:', err); // output to netlify function log
reject({ statusCode: 500, body: err.message });
})
});
}
const parkEndpoint = stateName => {
return new Promise(function(resolve, reject) {
fetch(`${park_api_url}${stateName}${api_key}`)
.then(response => {
if (!response.ok) { // NOT res.status >= 200 && res.status < 300
return reject({ statusCode: response.status, body: response.statusText });
}
return resolve(getJson(response))
})
.catch(err => {
console.log('parkEndpoint invocation error:', err); // output to netlify function log
reject({ statusCode: 500, body: err.message });
})
})
}
exports.handler = function(event, context) {
const stateName = event.queryStringParameters.stateName;
return Promise.all([alertEndpoint(stateName), parkEndpoint(stateName)])
.then(values => {
const [alertData, parkData] = values;
const parksWithAlerts = parkData.map(park => {
park.alertData = alertData.filter(alert => alert.parkCode === park.parkCode);
return park;
});
return {
statusCode: 200,
headers: { 'content-type': 'application/json' },
body: JSON.stringify(parksWithAlerts)
};
})
.catch(error => {
return error;
});
};
NOTE: If you are trying to hide the token, make sure to not deploy this from a public repository on Netlify.
Also, this code has not been tested 100%, so there may be some things to resolve. The response layout and structure is something I use in a few of my lambda functions on Netlify.