What function is passed to cb here? - javascript

So I have a small project containing both frontend (html) and backend (express: server, routers) parts. The project isn't that clean, so the its main operationality is launched directly in html section. And not much is clear to me here, especially what function is passed to cb (callback) here?
I have the following code in part of my html page within js project:
const $ = document.getElementById.bind(document)
const request = (path, cb) =>
fetch(path)
.then((res) => {
if (res.ok) return res.json()
throw Error('HTTP error: ' + res.status)
})
.then(cb)
.catch((err) => ($('result').innerHTML = err))
const main = async () => {
const pinRequired = new URLSearchParams(document.location.search).get('pin')
const id = await request(`./qrcode?pin=${pinRequired}`, (json) => {
const { qrbase64, deeplink, pin, id } = json
$('qrcode').innerHTML = `<img src="${qrbase64}" alt="Red dot" />`
$('deeplink').innerHTML = ` ${deeplink.slice(0, 90)}...`
$('pin').innerHTML = pin ? pin : 'Not requested'
return id
})
setInterval(() => request(`./status?id=${id}`, ({ status }) => ($('result').innerHTML = status)), 1000)
}
main().catch(console.log)
Is this (json)? I also don't know why it is in () round brackets, however, it is an object, it cannot be passed as a callback, right?
And I also have a code in another file, which contains /qrcode route of my website. There is a function (quite big, so i'm not posting it, just pointing that it doesn't return function that may be passed as a callback).
If this callback 100% is in another part of the code, as you think, please let me know.

If what you're asking about is this callback (json) => { ... } in the code below:
request(`./qrcode?pin=${pinRequired}`, (json) => {
const { qrbase64, deeplink, pin, id } = json
$('qrcode').innerHTML = `<img src="${qrbase64}" alt="Red dot" />`
$('deeplink').innerHTML = ` ${deeplink.slice(0, 90)}...`
$('pin').innerHTML = pin ? pin : 'Not requested'
return id
});
Then this is what is known as an arrow function. You can read about them here on MDN. They are a shortcut syntax for declaring a function that also has a number of implementation differences.
Note, there are some other issues in your code as request() does not return a promise so it does no good to use await on it and you won't get the id back from return id either.
Also note that the request library has been deprecated and generally shouldn't be used for new code. There is a list of alternatives here, all of which support promises natively. My favorite in that list is the got() library.

Related

How can I solve this error when doing the fetch with svelte?

Good morning, I have this problem, I have 2 functions: the unlockLine function activates a lock when an alert comes out,
and requests a password to be able to unlock it, the lock and unlock does generate it for me, but when I want to enter the password I get the following error: TypeError: Cannot read properties of undefined (reading 'password').
and I don't know how to fix it.
the getAuthorizedUserPassword method is the one that captures the response from the API
const getAuthorizedUserPassword = (AuthorizedUserPassword) => {
return PackagingApi.getAuthorizedUserPassword(AuthorizedUserPassword)
.then((response) => {
Isavailablepassword = response.data.password;
return isavailablepassword;
})
.catch(handleError);
};
const unlockLinewhile = () =\> {unlockLine()} //Constant that is executed at the moment of an alert() that in turn calls another constant.
`let Isavailablepassword = null;
const getAuthorizedUserPassword = (AuthorizedUserPassword) =\> {
return PackagingApi.getAuthorizedUserPassword(AuthorizedUserPassword)
.then((response) =\> {
Isavailablepassword = response.data.password;
return isavailablepassword;
})
.catch(handleError);
console.log(isavailablepassword);
};`
const unlockLine = () => { PackagingApi.SetStationBlocked(1,lineCode) //Bloqueamos toda la linea let imputpassword = prompt("Linea Bloqueada \n Ingresa la contraseña del supervisor", ""); //Entrada de contraseña getAuthorizedUserPassword(imputpassword) .then((response) => { if(response){ PackagingApi.SetStationBlocked(0, lineCode); } else{ alert("Contraseña Incorrecta \n Ingresa la contraseña Correcta para desbloquear"); unlockLine(); } });};
This is my function in JS to do the get
export const PackagingApi = (function (apiUrl) { apiUrl = 'http://localhost:5183'; return { getAuthorizedUserPassword : async (AuthorizedUserPassword) => HttpRequest.get(`${apiUrl}/api/Auth/${AuthorizedUserPassword}`), }; });
This is what the API gives me with postman
{ "data": { "password": true } }
I need that when it is true it is activated in the first IF and when it is false it enters the Else
Thank you so much.
I need help to solve the problem described with Svelte
Assuming PackagingApi.getAuthorizedUserPassword is issuing a plain fetch, it means that the response object does not provide access to the body's data. Instead, you need to request this data with one of the following methods:
text(): For plain text
json(): For JSON-formatted responses
etc
You can view all the methods in here.
This means that, in your particular case, the only thing you need to do is as follows:
PackagingApi.getAuthorizedUserPassword(AuthorizedUserPassword)
.then((response) => {
return response.json()
})
.then((data) => {
return data.password;
})
.catch(handleError);
Of course you can manipulate the Promises any way that suits you.
Bear in mind that if your returned data is not a properly-formatted JSON string, it will also make the request to fail.

React Native API FETCH Different names for each objects

I am connecting a REST api from React Native app. I have Json response with filename objects with different names but all the objects have same variables: filename, message, and display.
Number of objects changes with each request to API (REST), the names of objects in response are different depending on requests. But the variables in each object are same as above.
The information I need from this response is only filename text, but it will be acceptable if I get list of objects so I can read through the messages from errors.
The image shows how my objects look like.
This is my fetch request :
const getGists = async () => {
await axios
.get(`https://api.github.com/gists/public?per_page=30`)
.then((r) => {
let n;
for (n = 0; n < 30; n++) {
console.log(r.data[n].files.filename);
// console.log("____________________");
// console.log(r.data[n].owner.avatar_url);
// console.log("____________________");
// console.log(JSON.stringify(r.data[n].files));
}
})
.catch((e) => {
console.log("ERROR", e);
});
};
how is possible to get every filename from these requests even if object name is not the same in each iteration . Thanks for help
Working with the result of the API calls and some higher-order functions, this will work fine:
const getGists = async () => {
await axios
.get(`https://api.github.com/gists/public?per_page=30`)
.then((response) => {
const myDesireResult = response.data.reduce((acc, item) => {
const files = Object.values(item.files);
if (files.length > 1) {
files.forEach((file) => acc.push(file.filename));
} else {
acc.push(files[0].filename);
}
return acc;
}, []);
console.log(myDesireResult);
})
.catch((e) => {
console.log("ERROR", e);
});
};
Explanation:
in the then block, can get the API call result with result.data
with reduce function, looping through the data will start.
since the object in the files has different names, we can get the files with Object.values() easily.
Some of the files contain several items and most of them have just one item. so with checking the length of the file we can do proper action. if the files have more than one element, with another simple lop, we can traverse this file array easily.
Check the working example on codesandbox

How do I use the pipeline from stream-json to write to file, in nodeJs?

I'm trying to use stream-json to read a zip, unzip it, and then write it to file. I don't think I understand how to use the library.
Based on the link above, they have this example:
const {chain} = require('stream-chain');
const {parser} = require('stream-json');
const {pick} = require('stream-json/filters/Pick');
const {ignore} = require('stream-json/filters/Ignore');
const {streamValues} = require('stream-json/streamers/StreamValues');
const fs = require('fs');
const zlib = require('zlib');
const pipeline = chain([
fs.createReadStream('sample.json.gz'),
zlib.createGunzip(),
parser(),
pick({filter: 'data'}),
ignore({filter: /\b_meta\b/i}),
streamValues(),
data => {
const value = data.value;
// keep data only for the accounting department
return value && value.department === 'accounting' ? data : null;
}
]);
let counter = 0;
pipeline.on('data', () => ++counter);
pipeline.on('end', () =>
console.log(`The accounting department has ${counter} employees.`));
However I don't want to count anything, I just want to write to file. Here is what I have that works:
function unzipJson() {
const zipPath = Path.resolve(__dirname, 'resources', 'AllPrintings.json.zip');
const jsonPath = Path.resolve(__dirname, 'resources', 'AllPrintings.json');
console.info('Attempting to read zip');
return new Promise((resolve, reject) => {
let error = null;
Fs.readFile(zipPath, (err, data) => {
error = err;
if (!err) {
const zip = new JSZip();
zip.loadAsync(data).then((contents) => {
Object.keys(contents.files).forEach((filename) => {
console.info(`Writing ${filename} to disk...`);
zip.file(filename).async('nodebuffer').then((content) => {
Fs.writeFileSync(jsonPath, content);
}).catch((writeErr) => { error = writeErr; });
});
}).catch((zipErr) => { error = zipErr; });
resolve();
} else if (error) {
console.log(error);
reject(error);
}
});
});
}
However I can't easily add any processing to this, so I wanted to replace it with stream-json. This is my partial attempt, as I don't know how to finish:
function unzipJson() {
const zipPath = Path.resolve(__dirname, 'resources', 'myfile.json.zip');
const jsonPath = Path.resolve(__dirname, 'resources', 'myfile.json');
console.info('Attempting to read zip');
const pipeline = chain([
Fs.createReadStream(zipPath),
zlib.createGunzip(),
parser(),
Fs.createWriteStream(jsonPath),
]);
// use the chain, and save the result to a file
pipeline.on(/*what goes here?*/)
Later on I intend to add extra processing of the json file(s), but I want to learn the basics before I start throwing in extra functionality.
I can't produce a minimal example unfortunately, as I don't know what goes into the pipeline.on function. I'm trying to understand what I should do, not what I've done wrong.
I also looked at the related stream-chain, which has an example that ends like so:
// use the chain, and save the result to a file
dataSource.pipe(chain).pipe(fs.createWriteStream('output.txt.gz'));`
But at no point does the documentation explain where dataSource comes from, and I think my chain creates it's own by reading the zip from file?
How am I supposed to use these streaming libraries to write to file?
I don't want to count anything, I just want to write to file
In that case, you'll need to convert the token/JSON data stream back into a text stream that you can write to a file. You can use the library's Stringer for that. Its documentation also contains an example that seems to be more in line with what you want to do:
chain([
fs.createReadStream('data.json.gz'),
zlib.createGunzip(),
parser(),
pick({filter: 'data'}), // omit this if you don't want to do any processing
stringer(),
zlib.Gzip(), // omit this if you want to write an unzipped result
fs.createWriteStream('edited.json.gz')
]);

Async sometimes returning undefined

When calling the following method:
getLyrics: async function(song) {
const body = await this.getSongBody(song);
const lyrics = await cheerio.text(body('.lyrics'));
return lyrics;
}
as such:
genius.getLyrics('What a wonderful')
.then((res) => console.log(res))
.catch((err) => console.log(err.message));
Everything works fine and the lyrics of "What a wonderful world" by Louise Armstrong pops up in the console.
However, when I run the same code but without "await" in front of "cheerio.text..." sometimes the lyrics are produced and other times "undefined" shows up in the console. What has been making me scratch my head for a while now is that "cheerio.text..." does not return a promise (albeit "getSongBody" does), so to my understanding, there is no need to "wait" for it to finish.
I'm clearly missing something about async/await but have no idea what. Any help would be greatly appreciated!
Thanks
EDIT: Added a reproducible example as requested below:
const fetch = require('node-fetch');
const cheerio = require('cheerio');
// API
function geniusApi(token) {
this._token = token;
this._auth = {'Authorization': 'Bearer ' + this._token};
};
geniusApi.prototype = {
getSongURL : async function(search_keyword){
const res = await fetch('https://api.genius.com/search?q=' +
search_keyword,{headers: this._auth});
const body = await res.text();
const body_parsed = JSON.parse(body);
if (body_parsed.response.hits.length == 0){
console.log('No such song found');
throw Error('No such song found');
}
const url = body_parsed.response.hits[0].result.url;
return url;
},
getSongBody: async function (song){
const url = await this.getSongURL(song);
const response = await fetch(url);
const body = await response.text();
const body_parsed = cheerio.load(body);
return body_parsed;
},
getLyrics: async function(song) {
const body = await this.getSongBody(song);
const lyrics = cheerio.text(body('.lyrics'));
return lyrics;
}
}
// TEST EXAMPLE
const token =
'OTh1EYlsNdO1kELVwcevqLPtsgq3FrxfShIXg_w0EaEd8CHZrJWbWvN8Be773Cyr';
const genius = new geniusApi(token);
genius.getLyrics('What a wonderful')
.then((res) => console.log(res))
.catch((err) => console.log(err.message));
For anyone who ever stumbles upon the same issue, the problem in this case had nothing to do with async, promise or any other JS feature. It was merely a coincidence that the code had functioned correctly while using async, it later turned out that it didn't always work with async either.
The reason was simply that the Genius API that I was using to fetch the data, would return different source codes for identical API queries.
Two different source codes were returned, one contained a div called "lyrics" while the other did not. Therefore, sometimes the lyrics were found using cheerio, other times, they were not.

JavaScript Google Cloud Function: write Stripe values to Firebase

I'm new to JavaScript and I have written the following JS Google Cloud Function with the help of various resources.
This function handles a Stripe invoice.payment_succeeded event and instead of writing the entire data I am trying to save just both the sent period_start and period_end values back to the correct location in my Firebase DB (see structure below).
How can I write these two values in the same function call?
exports.reocurringPaymentWebhook = functions.https.onRequest((req, res) => {
const hook = req.body.type;
const data = req.body.data.object;
const status = req.body.data.object.status;
const customer = req.body.data.object.customer;
const period_start = req.body.data.object.period_start;
const period_end = req.body.data.object.period_end;
console.log('customer', customer);
console.log('hook:', hook);
console.log('status', status);
console.log('data:', data);
console.log('period_start:', period_start);
console.log('period_end:', period_end);
return admin.database().ref(`/stripe_ids/${customer}`).once('value').then(snapshot => snapshot.val()).then((userId) => {
const ref = admin.database().ref(`/stripe_customers/${userId}/subscription/response`)
return ref.set(data);
})
.then(() => res.status(200).send(`(200 OK) - successfully handled ${hook}`))
.catch((error) => {
// We want to capture errors and render them in a user-friendly way, while
// still logging an exception with StackDriver
return snap.ref.child('error').set(userFacingMessage(error));
})
.then((error) => {
return reportError(error, {user: context.params.userId});
});
});//End
HTTP type functions are terminated immediately after the response is sent. In your code, you're sending the response, then attempting to do more work after that. You will have to do all the work before the response is sent, otherwise it may get cut off.
If you just want to save the period_start and period_end values, instead of the entire data object, you can use the update() method (see https://firebase.google.com/docs/database/web/read-and-write#update_specific_fields).
You should then modify your code as follows. (Just note that it is not clear from where you receive the userId value, since you don't show the stripe_ids database node in your question. I make the assumption that it is the value at /stripe_ids/${customer}. You may adapt that.)
exports.reocurringPaymentWebhook = functions.https.onRequest((req, res) => {
const hook = req.body.type;
const data = req.body.data.object;
const status = req.body.data.object.status;
const customer = req.body.data.object.customer;
const period_start = req.body.data.object.period_start;
const period_end = req.body.data.object.period_end;
admin.database().ref(`/stripe_ids/${customer}`).once('value')
.then(snapshot => {
const userId = snapshot.val();
let updates = {};
updates[`/stripe_customers/${userId}/subscription/response/period_start`] = period_start;
updates[`/stripe_customers/${userId}/subscription/response/period_end`] = period_end;
return admin.database().ref().update(updates);
})
.then(() => res.status(200).send(`(200 OK) - successfully handled ${hook}`))
.catch((error) => {...});
});

Categories

Resources