I'm new to Node.js and I'm going to implement Google Fit REST API to my Node.js project and I wish to make it to update health data every 5 seconds (refer to const aggregated_data)
Here is my .get() method:
app.get("/starter", async (req, res) => {
const patientID = req.query.id;
/**
* If user record exists. Proceed without reuqesting authorisation again
*/
if (db.find((item) => item.id === patientID)) {
const user = db.find((item) => item.id === patientID);
let tokens = user.tokens;
let healthDataArray = [];
let allSessions = [];
console.log("isTokenExpired :>> ", isTokenExpired(tokens.tokens));
console.log("Now is ", Date.now());
if (isTokenExpired(tokens.tokens)) {
const result = await axios({
method: "POST",
url: "https://oauth2.googleapis.com/token", "Content-Type": "application/x-www-form-urlencoded",
data: {
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
refresh_token: tokens.tokens.refresh_token,
grant_type: "refresh_token",
},
});
console.log("Updated Token :>> ", result.data);
const patient_index = db.findIndex((item) => item.id === patientID);
let updated_patient_token = db[patient_index];
updated_patient_token.tokens.tokens.access_token = result.data.access_token;
updated_patient_token.tokens.tokens.expiry_date = Date.now() + result.data.expires_in * 1000;
updated_patient_token.tokens.tokens.scope = result.data.scope;
updated_patient_token.tokens.tokens.token_type = result.data.token_type;
console.log("Not-updated Database Token :>> ", tokens.tokens);
db[patient_index] = updated_patient_token;
tokens = db[patient_index];
console.log("Updated Database Token :>> ", tokens.tokens);
}
try {
const result = await axios({
method: "POST",
headers: {
authorization: "Bearer " + tokens.tokens.access_token,
},
"Content-Type": "application/json",
url: `https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate`,
data: {
aggregateBy: [
{
dataTypeName: "com.google.step_count.delta",
dataSourceId: "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps",
},
{
dataTypeName: "com.google.calories.expended",
dataSourceId: "derived:com.google.calories.expended:com.google.android.gms:merge_calories_expended",
},
{
dataTypeName: "com.google.heart_minutes",
dataSourceId: "derived:com.google.heart_minutes:com.google.android.gms:from_steps<-estimated_steps",
},
],
bucketByTime: { durationMillis: 86400000 },
startTimeMillis: Date.now() - 30 * 86400000,
endTimeMillis: Date.now(),
},
});
const sessions = await axios({
method: "GET",
headers: {
authorization: "Bearer " + tokens.tokens.access_token,
},
"Content-Type": "application/json",
url: `https://fitness.googleapis.com/fitness/v1/users/me/sessions`,
});
healthDataArray = result.data.bucket;
allSessions = sessions.data.session;
}catch (error) {
console.log("error :>> ", error.response);
}
const aggregated_data = {
non_session: healthDataArray,
session: allSessions,
};
console.log("New data fetched");
return res.json(aggregated_data);
}catch(error1){
console.log("error fetch new data :>> ", error1.response);
}
}else {
res.cookie("id", patientID).redirect("http://localhost:5000/auth");
}
});
My task is to use Cron Job to loop this method (which getting and posting the user's health data) once I getting into http://localhost:{PORT}/starter but I don't know how to call it into my cron.schedule and run correctly. Anyone can help?
Related
The bounty expires in 2 days. Answers to this question are eligible for a +100 reputation bounty.
Ganesh Putta is looking for an answer from a reputable source.
I have below function in frontend, I have to make some api call here in this function. When i checked the called function via command prompt, the server api call returns 400. but the function in frontend fetch always returning 200 instead of error.
Thanks in advance.
Please guide to how to correct response which is thrown from server call?
Here is the frontend function.
function processFile() {
var fileToLoad = document.getElementById("fileToLoad").files[0];
var url;
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent) {
var rows = fileLoadedEvent.target.result.split("\n");
for (var i = 0; i < rows.length - 1; i++) {
var cells = rows[i].split(",");
//alert(cells);
console.log("AgentteamID=" + cells[0] + " SkilltargetID=" + cells[1] + " flag=" + cells[2]);
url = "/updateAgentTeam?agentTeamID=" + cells[0] + "&skillTargetID=" + cells[1] + "&flag=" + cells[2],
//alert(url);
console.log("URL=" + url);
const response = fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
}).then(response =>
response.json().then(data => ({
data: "success",
status: response.status
})).then(res => {
var statusCode = JSON.stringify(res.status);
//$('#Success_comment').html(JSON.stringify(res)+"---"+url;);
//alert(url);
document.getElementById("Success_comment").value += JSON.stringify(res) + "---" + url;
console.log("final result " + JSON.stringify(res) + "---" + url);
}))
}
}
fileReader.readAsText(fileToLoad, "UTF-8");
}
Here is the Server side code. For now we are using only Flag A block
app.get("/updateAgentTeam", (req, res) => {
var skillTargetID = req.query.skillTargetID;
console.log("req.query.skillTargetID =" + req.query.skillTargetID);
var agentTeamID = req.query.agentTeamID;
var flag = req.query.flag;
var finalurl = "http://198.18.133.11/unifiedconfig/config/agentteam/" + agentTeamID;
var xml;
//console.log("finalurl ="+finalurl);
axios({
url: finalurl,
method: "get",
auth: {
username: "xxx",
password: "yyy"
},
})
.then(async(response) => {
xml = response.data;
//console.log("after calling xml is "+JSON.stringify(xml));
res.send(response.data);
if (flag === 'D') {
agentremovedXML = removeAgentFromXML(xml, skillTargetID);
//newxml=removeAgentFromXML(xml);
//console.log("Final Agent remove XML "+JSON.stringify(agentremovedXML));
postAgentToTeam(agentTeamID, agentremovedXML);
//setSuccessJSON();
} else if (flag === 'A') {
AgentXML = await generateAgentXML(skillTargetID);
console.log("Returned agent xml is " + JSON.stringify(AgentXML));
console.log("xml where agent to be add " + JSON.stringify(xml));
if (JSON.stringify(xml.agentCount) == 0) {
AgentXML = {
"agent": [AgentXML]
};
xml.agents = [AgentXML];
console.log("xml with zero agents " + JSON.stringify(xml));
} else {
xml.agents[0].agent.push(AgentXML);
console.log("Compare " + JSON.stringify(xml));
}
console.log("xml send to postAgentToTeam is " + xml);
postAgentToTeam(agentTeamID, xml);
//postAgentToTeam(agentTeamID,agentXML);
}
})
.catch((err) => {
res.status(400);
res.send(err.response.status);
console.log(err);
//setErrorJSON()
});
});
async function postAgentToTeam(agentTeamID, xml) {
var teamurl = "http://198.18.133.11/unifiedconfig/config/agentteam/" + agentTeamID;
//console.log("final XML is "+JSON.stringify(xml));
xml.agents = xml.agents[0].agent.map(agent => ({
agent: agent
}));
var updatedJSONwithAgentTags = JSON.stringify(xml, null, " ");
//console.log("newwwwwwwwwwwwwwwwwwwwww "+ updatedJSONwithAgentTags);
//return;
js2xml = json2xml(JSON.parse(JSON.stringify(xml)));
json2 = "<agentTeam>" + js2xml + "</agentTeam>";
//console.log("newwww converted XML "+json2);
response = await axios({
url: teamurl,
method: "put",
auth: {
username: "administrator#dcloud.cisco.com",
password: "C1sco12345"
},
data: json2,
headers: {
'Content-Type': 'application/xml; charset=utf-8'
}
})
.then(response => {
console.log("hellooo " + response.status);
})
.catch((err) => {
console.log(err.response.data.apiError);
console.log("error res is " + err.response.status);
});
}
There's a quite few things wrong.
Inside your first .then(async(response) => {, you set the xml to response.data then right away call res.send(response.data) (200) which is the end of the execution order for Express. However, you go on to do a bunch of other things after the res.send (200) is sent. You should not do that.
You need to restructure your code. Starting from the top-down keeping in mind that all promises need to be returned and that res.send() is the end of the block. Throwing a 400 after this won't matter since Express already sent the response to the client.
You're also mutating theresponse output from Axios which is bad practice. Create a new one if you need to mutate it:
const newResponse = { ...response };
Additionally, this mixing of .then().catch() with an initial await is not how you should handles promises and would cause problems.
Don't write them like this:
response = await axios({}).then().catch().
Either do this:
axios({ // <--- no await, no let response =
url: finalurl,
method: "get",
auth: {
username: "xxx",
password: "yyy"
},
})
.then(async(response) => {
// res.send, etc.
}).catch((e) => {
// handle errors
});
Or use try / catch blocks like this:
try {
const results = await axios({
url: teamurl,
method: "put",
auth: {
username: "administrator#dcloud.cisco.com",
password: "C1sco12345"
},
data: json2,
headers: {
'Content-Type': 'application/xml; charset=utf-8'
}
}); // <--- the end.
console.log({results});
} catch (e) {
// handle errors
console.log(e);
}
This issue only occurs with posts with multipart video, Posts with images and videos below 4MB are working, when posting to Posts API i get a response with Status OK and the post URN in the header but when i try getting the post data using the given URN i'm getting error 404.
Here is the function that i am using to upload the video to LinkedIn.
const uploadVideo = async (linkedinId, accessToken, videoUrl) => {
/* Fetching video from Google storage */
const videoData = await axios.get(videoUrl, { responseType: 'arraybuffer' });
const contentType = videoData.headers['content-type'];
const videoSize = videoData.headers['content-length'];
const url = 'https://api.linkedin.com/rest/videos';
const body = {
initializeUploadRequest: {
owner: `urn:li:organization:${linkedinId}`,
fileSizeBytes: Number(videoSize),
},
};
const headers = {
Authorization: `Bearer ${accessToken}`,
'X-Restli-Protocol-Version': '2.0.0',
'x-li-format': 'json',
'LinkedIn-Version': 202207,
};
const response = await axios.post(url, body, { headers, params: { action: 'initializeUpload' } });
const { uploadInstructions } = response.data.value;
const asset = response.data.value.video;
/* Uploading video */
try {
const uploadPromises = uploadInstructions.map(async ({ uploadUrl, firstByte, lastByte }) => {
const arrayBuffer = videoData.data.slice(firstByte, lastByte);
return axios({
url: uploadUrl,
method: 'POST',
data: arrayBuffer,
headers: {
'Content-Type': contentType,
},
maxBodyLength: Infinity,
maxContentLength: Infinity,
});
});
const uploadResponses = await Promise.all(uploadPromises);
const finalizeUploadBody = {
finalizeUploadRequest: {
video: asset,
uploadToken: '',
uploadedPartIds: uploadResponses.map((uploadResponse) => uploadResponse.headers.etag),
},
};
await axios.post(url, finalizeUploadBody, {
headers: {
...headers,
'Content-Type': 'application/json',
},
params: {
action: 'finalizeUpload',
},
});
} catch (error) {
throw error;
}
return asset;
};
Here is the function that i am using to publish the post to LinkedIn.
const publishContent = async (
linkedinId,
accessToken,
media,
) => {
const url = 'https://api.linkedin.com/rest/posts';
const body = {
author: `urn:li:organization:${linkedinId}`,
commentary: 'content',
visibility: 'PUBLIC',
lifecycleState: 'PUBLISHED',
distribution: {
feedDistribution: 'MAIN_FEED',
},
};
const asset = await uploadVideo(linkedinId, accessToken, media.urls[0], isPage);
body.content = {
media: {
title: 'Title',
id: asset,
},
};
const headers = {
Authorization: 'Bearer ' + accessToken,
'X-Restli-Protocol-Version': '2.0.0',
'x-li-format': 'json',
'LinkedIn-Version': 202207,
};
return axios.post(url, body, { headers });
};
I was always using plain JS und fetch call to handle API, they are working fine, now I want to replace all fetch with axios, so far the axios get calls are all working, but the axios post call are not, please guide:
the original fetch post from client side is like this, i need to send 3 values to server
const postTrip = async(location = '', daysToGo = '', notes ='') => {
const res = await fetch('http://localhost:7777/addData', {
method: 'POST',
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({location, daysToGo, notes}),
})
if (res.status >= 400 && res.status < 600) {
throw new Error("Bad response from server");
}
updateUI(daysToGo);
}
from server side
app.post('/addData', async (req, res) => {
try {
const city = req.body.location;
const dayLength = req.body.daysToGo;
const memo = req.body.notes;
let geo = await getGeo(city);
let weather = await getWeather(geo.lat, geo.lng, dayLength);
let image = await getImage(city);
const newEntry = {
geo,
weather,
image,
memo
}
projectData = newEntry;
res.status(201).send(projectData);
now I try to change client fetch post to axios post like this
const postTrip = async(location = '', daysToGo = '', notes ='') => {
const res = await axios('http://localhost:7777/addData', {
method: 'POST',
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json"
},
data: JSON.stringify({location, daysToGo, notes}),
})
if (res.status >= 400 && res.status < 600) {
throw new Error("Bad response from server");
}
updateUI(daysToGo);
}
and change the server side like this:
app.post('/addData', async (req, res) => {
try {
const city = req.data.location;
const dayLength = req.data.daysToGo;
const memo = req.data.notes;
let geo = await getGeo(city);
let weather = await getWeather(geo.lat, geo.lng, dayLength);
let image = await getImage(city);
const newEntry = {
geo,
weather,
image,
memo
}
projectData = newEntry;
res.status(201).send(projectData);
it dosen't work, the server didn't get the three values from front, where is wrong?
With axios you don't have to stringify the body.
const postTrip = async(location = '', daysToGo = '', notes ='') => {
const res = await axios('http://localhost:7777/addData', {
method: 'POST',
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json"
},
data: {location, daysToGo, notes},
})
if (res.status >= 400 && res.status < 600) {
throw new Error("Bad response from server");
}
updateUI(daysToGo);
}
auth authentication but i'm having an issue with sessions
My next-auth version is 4.0.0-beta.4(also tried beta.7 with same results)
I have my own JWT token backend that takes a username and password. And gives back an object with accesstoken, refreshtoken, expiretime and resfresh-time
So im trying to use that backend to handle session state with next-auth.
I manage to set the cookie "next-auth.session-token". But the session is always undefined when i'm trying to getSession.
And i don't have any sessions in my firefox browser.
const options = {
providers: [
Credentials({
name: "Credentials",
credentials: {
username: {
label: "Username",
type: "text"
},
password: {
label: "Password",
type: "password"
}
},
session: {
jwt: true,
maxAge: 30 * 24 * 60 * 60 // the session will last 30 days
},
authorize: async (credentials) => {
const tokenUrl = "http://192.168.0.8:8081/api/auth/token"
const token = await fetch(tokenUrl, {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
username: credentials.username,
password: credentials.password
})
})
.then(res => res.json())
console.log("token: ", token)
if (token) {
const userUrl = "http://192.168.0.8:8081/admin/user/username/" + credentials.username;
const user = await fetch(userUrl, {
method: "GET",
mode: "cors",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + token.access_token
}
}).then(res => res.json())
return {
token,
user
};
} else {
return null;
}
}
}),
],
session: {
jwt: true
},
pages: {
signIn: "/login",
},
secret: "TEST",
callbacks: {
async jwt({ token, user }) {
// Initial call
if (user) {
return {
accessToken: user.token.access_token,
accessTokenExpires: Date.now() + user.token.expire_time * 1000,
refreshToken: user.token.refresh_token,
user: user.user,
}
}
// Subsequent calls
return token;
},
async session(session) {
session.name = session.token.user.fullName
session.accessToken = session.token.accessToken
session.refreshToken = session.token.refreshToken
return session;
}
}
}
Here i'm trying to get the session after logging in
export default function Home() {
const { data: session } = getSession();
console.log("session: ", session)
return (
< div >
</div >
)
}
Any ideas?
My problem was that I was using the wrong method. I needed to use the useSession method instead of getSession. Then it worked. 🙂
I am doing some nested axios calls as in order to create the object i want i need to fire off a couple of different API's. My problem is that when i call setState, the state will start updating before all requests have finished so my table will populate entry by entry which does not look nice.
here is my code:
fetchServices = async ()=> {
this.setState({isLoading: true})
await axios({
method: 'get',
url :getApiUrl(),
headers:{
"Accept": "application/json"
}
})
.then( async response => {
let Data: any[] = []
response.data.Message.forEach(async (e: any) => {
await axios({
method: 'get',
url: getApiUrl() + "/" + e.organisationErn + "/services",
headers:{
"Accept": "application/json"
}
}).then( async response => {
console.log(response)
if(response.data.Message !== "No services found"){
response.data.Message.forEach(async(e:any)=>{
let orgName = await axios({
method: 'get',
url: getApiUrl() + "/" + e.organisationErn,
headers:{"Accept": "application/json"}})
.then(response => {return response.data.Message.organisationName});
let entry = {
servicename: { text: e.serviceName },
servicetype: { text: e.serviceTypeDescription },
organisation: { text: orgName },
};
Data.push(entry);
this.setState({ tableData: Data });
})
};
});
});
setTimeout(()=>{this.setState({isLoading: false})}, 100)
}).catch(error => {
alert(error)
});
};
Well you are pushing your data one by one. You can use Promise.all to await all requests complete then populate your state.
if (response.data.Message !== "No services found") {
const promises = response.data.Message.map((e: any) => {
axios({
method: 'get',
url: getApiUrl() + "/" + e.organisationErn,
headers: {
"Accept": "application/json"
}
})
.then(response => {
return response.data.Message.organisationName
})
.then(org => {
return {
servicename: {
text: e.serviceName
},
servicetype: {
text: e.serviceTypeDescription
},
organisation: {
text: org
},
};
});
});
const Data = await Promise.all([...promises]);
this.setState({ tableData: Data });
BTW there may be some parentheses errors.
I think its better to get the result from each axios request and use it at the end, instead of using then
like
const result1= await axios.get(...);
const result1= await axios.get(...);
const result1= await axios.get(...);
setState({ tableData: Data });
you can also refer https://medium.com/better-programming/how-to-use-async-await-with-axios-in-react-e07daac2905f