I'm currently using Node.js to fetch an API data and converting it into my own Express.js API server to send my own data (The 2 APIs I'm using changes the structure sometime and I have some users that need to keep the same structure).
So here is the code I'm using
app.get('/app/account/:accountid', function (req, res) {
return fetch('https://server1.com/api/account/' + req.params.accountid)
.then(function (res) {
var contentType = res.headers.get("content-type");
if (contentType && contentType.includes("application/json")) {
apiServer = 'server1';
return res.json();
} else {
apiServer = 'server2';
throw "server1 did not reply properly";
}
}).then(server1Reconstruct).then(function (json) {
res.setHeader('Content-Type', 'application/json');
return res.send(json);
}).catch(function (err) {
console.log(err);
}).then(function () {
if (apiServer == 'server2') {
server2.fetchAccount({
accountID: [Number(req.params.accountid)],
language: "eng_us"
})
.then(server2Reconstruct)
.then(function (json) {
res.setHeader('Content-Type', 'application/json');
return res.send(json);
}).catch(function (err) {
console.log(err);
});
}
});
})
To quickly explain the code: I call server1 through a normal Fetch this answer might be {} which is where I have a problem. If the accountid doesn't exist the server returns an JSON response with no errors to grab...
What should I do to be able to catch it... And If I catch it switch to server 2.
(Don't be too confused about server2 call as it's another package).
If I understand your problem correctly, you should follow those steps :
fetch the initial API
call the .json() method on the result - which returns a promise
deal with the json response in the first .then(json => ...), and here check if the result is {} then call server2, else call server1
BTW, your code looks very messy with all those then and catch, I recommend putting some stuff into functions, and using async/await if you can.
Here is some pseudo-code sample that you could use :
function server2Call() {
return server2.fetchAccount({
accountID: [Number(req.params.accountid)],
language: 'eng_us'
})
.then(server2Reconstruct)
.then(function (json) {
res.setHeader('Content-Type', 'application/json');
return res.send(json);
}).catch(function (err) {
console.log(err);
});
}
app.get('/app/account/:accountid', function (req, res) {
return fetch('https://server1.com/api/account/' + req.params.accountid)
.then(res => {
var contentType = res.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return res.json();
} else {
server2Call()
}
})
.then(json => {
res.setHeader('Content-Type', 'application/json');
if (json is {}) return server2Call()
else return res.send(json);
}).catch(function (err) {
console.log(err);
})
});
Related
I am playing around with the alpha vantage API and I am having trouble extracting the data in the else statement for viewing on the front end.
Here is my express route:
app.get('/', (req, res) => {
var url = 'https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=IBM&interval=5min&apikey=apikey';
request.get({
url: url,
json: true,
headers: { 'User-Agent': 'request' }
}, (err, resp, data) => {
if (err) {
console.log('Error:', err);
} else if (resp.statusCode !== 200) {
console.log('Status:', resp.statusCode);
} else {
// data is successfully parsed as a JSON object:
// console.log(data);
}
})
res.render("index");
})
I want to pass the data variable in the else statement to res.render("index" {//get data into here});
I have tried assigning the data variable to another variable outside of request.get({}) but it does not seem to work. Any suggestions? :)
request.get is an asynchronous function, it means that everything inside the callback function below won't be executed immediately, it will wait until the request.get finish calling the endpoint and return the data then callback function will be executed.
// the callback function of `request.get`
(err, resp, data) => {
if (err) {
console.log('Error:', err);
} else if (resp.statusCode !== 200) {
console.log('Status:', resp.statusCode);
} else {
// data is successfully parsed as a JSON object:
// console.log(data);
}
})
In terms of execution flow, your res.render("index"); will be executed first before the callback function of request.get (it waits until the endpoint call finished), that's why you couldn't access data.
So, in order to res.render to access data, it should be put inside callback function so
(err, resp, data) => {
// ...other code
} else {
res.render('index', { data });
}
})
good reference to read about asynchronous https://www.freecodecamp.org/news/nodejs-eventloop-tutorial/
You can render it in the else statement.
app.get('/', (req, res) => {
var url = 'https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=IBM&interval=5min&apikey=apikey';
request.get({
url: url,
json: true,
headers: { 'User-Agent': 'request' }
}, (err, resp, data) => {
if (err) {
console.log('Error:', err);
} else if (resp.statusCode !== 200) {
console.log('Status:', resp.statusCode);
} else {
res.render("index", {data}) // Change to something else
}
})
}}
App.js
app.get('/getCus', function (req, res) {
var id= req.query;
cus_controller.getCus(id,function(response) {
res.json(response);
});
});
cus_controller.js:
module.exports ={
getCus: function (id, callback) {
getCus = function () {
getOneCus(id).then(result => {
callback(result);
}).catch(err => {
callback(err)
})
}
process.nextTick(getCus);
},
}
async function getOneCus(id) {
auth.authClient(function (err, client) {
if (client) {
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
}
getCus(id,client, callback);
}
else {
console.error(err);
}
})
}
var getCus = (id, client, callback) => {
client
.invokeApi(null, `/cus/${id}`, 'GET')
.then(function (result) {
console.log(result.data);
return result.data
})
.catch(function (result) {
if (result.response) {
console.dir({
status: result.response.status,
statusText: result.response.statusText,
data: result.response.data
});
} else {
console.log(result.message);
}
});
}
in getCus method getting a response in the console. however, couldn't get a response in postman.it shows 200 status code but didn't get a response. Someone help me, please. I could not find any solution for this.i tried many methods like return data and res.send(data).
You're passing a callback function to getCus, but you never use it. It looks like you meant call it instead of return the result:
client
.invokeApi(null, `/cus/${id}`, 'GET')
.then(function (result) {
console.log(result.data);
callback(result.data); // <-- here
})
Alternatively, if you return the result as you currently do, then you wouldn't pass a callback to getCus but would instead use a .then() structure:
cus_controller.getCus(id).then(function(response) {
res.json(response);
});
But be sure to also return the top-level Promise by returning the call to client.invokeApi:
return client // <-- here
.invokeApi(null, `/cus/${id}`, 'GET')
.then(function (result) {
console.log(result.data);
return result.data
})
I'm refactoring my code to remove a "callback hell" using Promises, but encountered an error that I cannot pass. My code receives list of IDs and processes them making few database calls, that is why I had this "callback hell".
Everything worked fine until Promises. The res is equal 0 when I had to respond back to the client.
function processVMDelete(returnedVMIDs){
return new Promise((resolve, reject) => {
var mariasqlClient = dbConnection();
mariasqlClient.query( sqlUpdateDELETE_STATE_ByVMID, [
'DELETE',
returnedVMIDs
], function(err, rows) {
if (err){
reject(err);
}
console.log('finish update');
// dont' need to return anything here
resolve(0);
});
mariasqlClient.end();
});
}
function getListExpVM(){
return new Promise((resolve, reject) => {
var vmList = [];
var mariasqlClient = dbConnection();
mariasqlClient.query( sqlSearch_ByUSERNAMEAndSTATE, [
requesterUsername,
'ACTIVE'
], function(err, rows) {
if (err){
reject(err);
}
vmList = filterExpiredVMs(rows);
var response = {
status : 200,
success : 'Successfull',
data : vmList,
requester: requesterUsername
};
resolve(response);
});
mariasqlClient.end();
});
}
router.post('/processVMs', function(req, res) {
var returnedVMIDs = JSON.parse(req.body.data);
processVMDelete(returnedVMIDs)
.then(res => {
console.log('done');
// check if there is more available for the user:
getListExpVM()
.then(response => {
console.log('sending back list of VMs');
//===>>> ERROR HERE: res.end is not a function
res.end(JSON.stringify(response));
})
.catch(err => {
console.log('error', err.message);
logger.error("Error getting expired VMs: " + err.message);
//===>>> ERROR HERE: res.send is not a function
res.status(500).send({error: err.message})
});
})
.catch(err => {
console.log('error', err.message);
logger.error("Error processing VMs: " + err.message);
//===>>> ERROR HERE: res.send is not a function
res.status(500).send({error: err.message})
});
});
You've redefined res with this:
processVMDelete(returnedVMIDs)
.then(res => {...})
This will hide the higher scoped res associated with the overall request (the one you need to use for res.end()). Change the name of this one to something else like result and then change the corresponding references that use this result.
I send data from my input fields to my api:
$.ajax({
url: '/api/login',
type: 'GET',
dataType: 'json',
ContentType: 'application/json',
data: {formData},
success: (data) => {
console.log('SUCCESS')
console.log(data)
this.setState({
isInProcess: false
})
},
error: (jqXHR) => {
console.log(jqXHR)
console.log('ERROR')
this.setState({isInProcess: false})
}
})
on my server-side I have a function to see if I have required user in db:
async function findUser(data) {
try {
const user = await User.findOne({email: data.email,
password: data.password})
console.log('User was found')
return { user }
} catch (err) {
console.log('error', err)
throw err
}
}
which will be executed here:
app.get('/api/login', async (req, res) => {
const data = req.query
try {
const foundUserData = await findUser(data.formData)
return res.json(foundUserData)
} catch (err) {
return res.status(400).json(err)
}
})
It works fine, but if a user wasn't found in db i sends success anyway. Why?
await findUser(data.formData) won't throw error, return either null or user object. You may check something following
app.get('/api/login', async (req, res) => {
const data = req.query
try {
const foundUserData = await findUser(data.formData)
if(foundUserData && foundUserData.user) {
return res.json(foundUserData)
} else {
return res.status(400).json({message: 'User not found'});
}
} catch (err) {
return res.status(500).json(err)
}
})
It sends success because none of your queries error'ed, just because it didn't find anything does not mean that the query failed because it obviously succeeded in finding out if what ever you're looking for exists or not.
To send an error in case of not found you need to check if response is empty in which case you want to send error
When no user is find you get a null value. You may try to put more logic on your success parameter with that for example:
success: function (data) {
if(!!data && data != null) {
alert('Success');
} else {
alert('No data');
}
}
I have tried everything and can't figure out what i am doing wrong. I have no problem posting data from the client to the server but the other way around i can't get it to work.
The only response i get in my client is ReadableByteStream {}.
This is my code on the client:
export function getAllQuestionnairesAction(){
return (dispatch, getState) => {
dispatch(getAllQuestionnairesRequest());
return fetch(API_ENDPOINT_QUESTIONNAIRE)
.then(res => {
if (res.ok) {
console.log(res.body)
return dispatch(getAllQuestionnairesSuccess(res.body));
} else {
throw new Error("Oops! Something went wrong");
}
})
.catch(ex => {
return dispatch(getAllQuestionnairesFailure());
});
};
}
This is my code on the server:
exports.all = function(req, res) {
var allQuestionnaires = [];
Questionnaire.find({}).exec(function(err, questionnaires) {
if(!err) {
console.log(questionnaires)
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ a: 1 }));
//res.json(questionnaires)
}else {
console.log('Error in first query');
res.status(400).send(err);
}
});
}
I'm doing some guesswork here, since I'm not sure what flavor of fetch you are currently using, but I'll take a stab at it based on the standard implementation of fetch.
The response inside the resolution of fetch typically does not have a directly readable .body. See here for some straight forward examples.
Try this:
export function getAllQuestionnairesAction(){
return (dispatch, getState) => {
dispatch(getAllQuestionnairesRequest());
return fetch(API_ENDPOINT_QUESTIONNAIRE)
.then(res => {
if (res.ok) {
return res.json();
} else {
throw new Error("Oops! Something went wrong");
}
})
.then(json => {
console.log(json); // response body here
return dispatch(getAllQuestionnairesSuccess(json));
})
.catch(ex => {
return dispatch(getAllQuestionnairesFailure());
});
};
}