Koa.js always get Not Found 404 - node.js

I develop in Koa and I use Firebase to messaging, because of a real-time database. When I want to get messages from firebase I get Not found, but in console.log() it shows me.
This is my function to getConversation(Messages)
async getConversation(conversationName, callback) {
var ref = await admin.database().ref(`messages/${conversationName}`)
await ref.on('value', (snapshot, prevChildKey) => {
var newPost = snapshot.val()
let values = Object.values(newPost)
callback(values)
})
}
Then I call it in another controller like this
async getMessages(ctx) {
const id = ctx.params.id
const nameOfConversation = await ctx.db.Conversation.findById(id)
await firebaseIndex.fbController.getConversation(nameOfConversation.name, response => {
console.log(response)
ctx.body = response //TODO
})
}
At the last, I call it in routes.
router.get('/getConversation/:id', middlewares.isAuthenticate, controllers.userConversation.getMessages)
I always get body Not found.
Do anybody know how I can solve it?

I solved it.
async getMessages(ctx) {
const id = ctx.params.id
const nameOfConversation = await ctx.db.Conversation.findById(id)
ctx.body = await new Promise((resolve, reject) => {
firebaseIndex.fbController.getConversation(nameOfConversation.name, async response => {
resolve(response)
})
})
}
ctx.body has to have a Promise.

Related

Push Data to MongoDB on Google SignIn Firebase

I wanted to write a method where onClick the google sign in starts and after successful sign in it makes a post request to my API.But the weird problem is 30% of the times the sign in data doesnt come to mongo db.I even called signout function in the catch block.Please help if someone notice any error!!
const Hero = () => {
const [user, setUser] = useState(null);
const [fetchUser, setFetchUser] = useState(null);
const handleGoogleSignIn = () => {
const googleProvider = new GoogleAuthProvider();
signInWithPopup(auth, googleProvider)
.then(async (result) => {
console.log(result);
try {
const { data } = await axios.post(
"https://myAPIherokuapp.com/api/v1/9c142e80023e07c3/registerUser",
{ name: result.user.displayName, email: result.user.email }
);
console.log(data);
} catch (err) {
console.log(err);
signOut(auth)
}
})
.catch((error) => {
console.log(error);
});
};
Maybe try async/await at the handleGoogleSignIn level? e.g.
const handleGoogleSignIn = async () => {
const googleProvider = await new GoogleAuthProvider();
const userResult = await signInWithPopup(auth, googleProvier);
await axios.post('url', userResult);
...
}
I think that should help?

Getting right fetch result from previous async fetch API functions

Hi I don't understand why getFlyByTime() function is giving me an ERR_INVALID_URL.
All the way upto getFlyByTime() I am getting the right results and coordinates.
Any advice would be appreciated,
Thank you
import fetch from "node-fetch";
let myIP = ''
let myLocation = ''
let flyByInformation = ''
const findIP = 'https://api.ipify.org/?format=json'
const geolocation = 'http://ipwho.is/'
const issFly = `https://iss-pass.herokuapp.com/json?`
const getMyIP = async function() {
let response = await fetch(findIP);
let data = await response.json()
return data.ip
}
const getMyGeoLocation = async function() {
let response = await fetch(geolocation + myIP);
let data = await response.json()
let resURL = `https://iss-pass.herokuapp.com/lat=${data.latitude}&lon=${data.longitude}`
return resURL;
}
const getFlyByTime = async function() {
let response = await fetch(myLocation);
console.log(response)
let data = await response.json()
return data;
}
getMyIP()
.then(data => {
myIP = data
}).catch(err => console.log('gmi error', err))
getMyGeoLocation()
.then(data => {
myLocation = data;
console.log(myLocation);
}).catch(err => console.log('gml error', err))
getFlyByTime()
.then(data => {
flyByInformation = JSON.parse(data);
console.log('flyby', flyByInformation);
}).catch(err => console.log('gflt error', err))
You are trying to use the myLocation and myIP values BEFORE they have been filled. Your functions return a promise before their work is done. Not until that promise has been fulfilled are the resolved values available for you to use.
As such, you must sequence your operations. It is generally easiest to do this with await. Here's an example shown below:
import fetch from "node-fetch";
const findIpURL = 'https://api.ipify.org/?format=json'
const geolocationURL = 'http://ipwho.is/'
const issFly = `https://iss-pass.herokuapp.com/json?`
async function fetchJSON(url) {
const response = await fetch(url);
if (response.ok) {
return response.json();
} else {
throw new Error(`Request failed, status ${response.status}`, { cause: response });
}
}
async function getMyIP() {
const data = await fetchJSON(findIpURL);
return data.ip;
}
function getMyGeoLocation(myIP) {
return fetchJSON(geolocationURL + myIP);
}
async function getFlyInfo(lat, long) {
let resURL = `https://iss-pass.herokuapp.com/lat=${lat}&lon=${long}`;
const flyInfo = await fetchJSON(resURL);
return flyInfo;
}
async function getFlyByTime() {
const myIP = await getMyIP();
console.log(myIP);
const myLocation = await getMyGeoLocation(myIP)
console.log(myLocation.latitude, myLocation.longitude);
return getFlyInfo(myLocation.latitude, myLocation.longitude);
}
getFlyByTime().then(flyInfo => {
console.log(flyInfo);
}).catch(err => {
console.log(err);
});
When I run this, the last getFlyInfo() request ends up returning a text/plain response that just says "Not Found" and the status is a 404. So, either the URL isn't being built properly in my version of the code or something is amiss in that last part.
But, hopefully you can see how you sequence asynchronous operations with await in this example and you can make that last part do what you want it to.

Client network socket disconnected before secure TLS connection was established aws lambda nodejs

--> I have a basic set up of lambda function with eventBridge.this function is invoked after every 2 minute. There I have tournaments.txt file which has 35 tournaments ID and for each tournament ID I am fetching data from an api.
--> Then I am saving those fetched data to database using another serverless routes.
Now in the cloudwatch log, my lambda function is giving error attached as screenshot below
my lambda function code
const axios = require("axios");
const fs = require("fs");
const writeResult = async (id) => {
console.log(id);
try {
const res = await axios.get(`${BASE_URL}/${id}.xml?json=1`);
if (res) {
const matches = res?.data?.commentaries?.tournament?.match;
if (Array.isArray(matches)) {
await Promise.all(
matches.map(async (m) => {
try {
await axios.post(
"https:example.com//route1",
m
);
await axios.post(
"https:example.com//route2",
m
);
await axios.post(
"https:example.com//route3",
m
);
await axios.post(
"https:example.com//route4",
m
);
await axios.post(
"https:example.com//route5",
m
);
await axios.post(
"https:example.com//route6",
m
);
} catch (error) {
console.log(error.message);
}
})
);
}
} catch (error) {
console.log(error.message);
}
};
exports.handler = async () => {
const ids = fs
.readFileSync("tournaments.txt", "utf-8")
.replace(/\r/g, "")
.trim()
.split("\n");
Promise.all(
ids.map((id) => {
writeResult(id);
})
);
return "finally done";
};
What is the probable issue here? I've done some research but did not find any helpful solution.
I've solved the issue. just added await before Promise.all() and now everything is working fine

async/promise with multiple api calls

I kind of understand the differences between callbacks, promises and async await, but I'm not quite sure how to apply this to my problem.
I stripped away a lot of the code, but basically I have an app running with an endpoint that needs to execute 3 functions (maybe I need a 4th?) and also send a "res.end()" within 3 seconds. The 3 functions are dependent on each other. Do I need to chain these functions? My main() seems completely wrong.
deleteRule() has to run and finish first
createRule() must run after deleteRule() has completed
orderRule() must run after createRule() has completed
router.post('/', function (req, res) {
async function deleteRule() {
axios.delete(DeleteURL, {auth: auth, httpsAgent: agent})
.then(response => {
let deleteRes = response.data
console.log(deleteRes)
})
}
const list = './jsons/list.json'
async function createRule() {
fs.readFile(list, 'utf-8', function(err, data) {
if (err) throw err
var thestuff = JSON.parse(data)
axios.post(CreateURL, thestuff, {auth: auth, httpsAgent: agent})
.then(response => {
let createRes = response.data
console.log(createRes)
})
})
}
async function orderRule() {
axios.put(usOrderURL, theOrder, {auth: auth, httpsAgent: agent})
.then(response => {
let orderRes = response.data
console.log(orderRes)
})
}
async function main() {
const deleteListResult = await deleteRule();
const createListResult = await createRule();
const orderListResult = await orderRule();
}
main();
// res.end must finish in 3 seconds from the initial post on the first line
res.end()
})
The then() calls return promises, but you don't do anything with them. You should either await them, or return them.
Since you declared your functions as async, make use of await in them -- that is the whole point of the async keyword:
async function deleteRule() {
let response = await axios.delete(DeleteURL, {auth: auth, httpsAgent: agent});
console.log(response.data);
return response.data;
}
Make a similar change to the other two rule-functions.
import fs from 'fs-extra'
const list = './jsons/list.json'
async function deleteRule() {
const response = await axios.delete(DeleteURL, {auth: auth, httpsAgent: agent})
const deleteRes = response.data
console.log(deleteRes)
return deleteRes
}
async function createRule() {
const data = await fs.readFile(list, 'utf-8')
const theStuff = JSON.parse(data)
const response = await axios.post(CreateURL, theStuff, {auth: auth, httpsAgent: agent})
const createRes = response.data
console.log(createRes)
return createRes
}
async function orderRule() {
const response = await axios.put(usOrderURL, theOrder, {auth: auth, httpsAgent: agent})
const orderRes = response.data
console.log(orderRes)
return orderRes
}
router.post('/', async function (req, res) {
const deleteListResult = await deleteRule();
const createListResult = await createRule();
const orderListResult = await orderRule();
// res.end must finish in 3 seconds from the initial post on the first line
res.end()
})

How to get Express Node route to wait for function before rendering

I am trying to get a route to wait for an async function in another module to return before render runs, but no matter what I do, res.render always runs first.
This is my current code, which actually just freezes and never loads:
router.get('/', function(req, res, next) {
try {
const cities = spreadsheet.getData()
} catch(err) {
console.log(err)
}
res.render('index', { cities: cities})
})
and the function it is waiting for is this:
exports.getData = function () {
parsedData = [];
accessSpreadsheet().then(function(data) {
console.log(parsedData)
return parsedData;
});
};
const accessSpreadsheet = async() => {
await doc.useServiceAccountAuth({
client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
private_key: process.env.GOOGLE_PRIVATE_KEY,
});
const loadedDoc = await doc.loadInfo();
sheet = await doc.sheetsByIndex[0];
const cells = await sheet.loadCells(allCells[cellsIndex]);
const data = await parseData();
const moreCells = await checkNextCells()
return;
}
The render runs first, and the parsedData prints in the console. I also tried making the route async, and I tried res.render inside a callback. Is there any way to make this work?
Since accessSpreadSheet is an async function, you either need to await or return the promise (as suggested by Patrick Roberts in the comment), in getData function, and similarly in the router.
Using async await you can update your code as below (not tested)
exports.getData = async function () {
parsedData = [];
parsedData = await accessSpreadSheet();
return parsedData;
};
const accessSpreadsheet = async() => {
await doc.useServiceAccountAuth({
client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
private_key: process.env.GOOGLE_PRIVATE_KEY,
});
const loadedDoc = await doc.loadInfo();
sheet = await doc.sheetsByIndex[0];
const cells = await sheet.loadCells(allCells[cellsIndex]);
const data = await parseData();
const moreCells = await checkNextCells()
return;
}
And in the router
router.get('/', async function(req, res, next) {
let cities;
try {
cities = await spreadsheet.getData()
} catch(err) {
console.log(err)
}
res.render('index', { cities: cities})
})
In your router, spreadsheet.getData() being async, you need to handle it with async/wait, which will require your callback to be async.
router.get('/', async function(req, res, next) {
try {
const cities = await spreadsheet.getData();
res.render('index', { cities: cities}) // moved this to inside a try block
} catch(err) {
console.log(err)
// you need to handle the exception here, return error message etc
}
})
In getData, you need to return a promise that will be resolved when called in router.
exports.getData = async function () {
let parsedData = [];
try {
parsedData = await accessSpreadsheet();
} catch (exc) {
// handle exception here
}
return parsedData;
};
finally in accessSpreadsheet(), I do not see where you return the data parsed.
const accessSpreadsheet = async() => {
try{
await doc.useServiceAccountAuth({
client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
private_key: process.env.GOOGLE_PRIVATE_KEY,
});
let loadedDoc = await doc.loadInfo();
let sheet = await doc.sheetsByIndex[0];
let cells = await sheet.loadCells(allCells[cellsIndex]); // cellsIndex is not defined
let data = await parseData(); // are you to pass the sheet? do not know how parsedData() works
let moreCells = await checkNextCells()
return data; // assuming data is what is meant to be returned
} catch(exc) {
// probably return null or re-raise exception
}
}
It is important to always use try/catch or then/catch when dealing with async code in NodeJS.
Hope it sheds some light!

Resources