I want to getUrl but it says getUrl is not defined.
The full script is
async function run(title, url) {
const keyword = [
url
]
var getUrl;
const result = await getUrl(keyword + "")
console.log(result)
const text = await getText(result)
fs.writeFile('./textfile' + (title) + '.txt', text, err => {
if (err) {
console.error(err)
return
}
//file written successfully
})
}
//run("Title", "Url")
I expected to get URL from the code but it only shows error and I cannot solve it.
Related
I'm trying to unit test this function.... following the documentation.
Any ideas why i'm getting this error? According to the documentation we can see it being called this way... What am I missing. https://jestjs.io/docs/en/bypassing-module-mocks
Thankx
async function isValid(pair) {
const path = process.env.PATH;
const query = '/check';
const requestOptions = ccyServiceRequestOptions(pair);
try {
const response = await fetch(path + query, requestOptions);
const json = await response.json();
return json.result.pair === pair;
} catch (err) {
if (err instanceof TypeError) {
return false;
}
else {
log.error(err);
throw err;
}
}
}
------------------------------------------------------------------------------------------
jest.mock('node-fetch');
const fetch = require('node-fetch');
const {Response} = jest.requireActual('node-fetch');
beforeEach(() => {
jest.clearAllMocks()
})
it('should call with valid url', async () => {
const pair = 'EURUSD';
fetch.mockReturnValue(Promise.resolve(new Response({})));
await ccyPairIsValid(pair);
expect(fetch).toHaveBeenCalled();
expect(fetch.mock.calls[0][0]).toHaveBeenCalledWith(process.env.PATH + '/check');
})
Error: expect(received).toHaveBeenCalledWith(...expected)
Matcher error: received value must be a mock or spy function
Received has type: string
Received has value: "http://localhost:8000/check"
You are calling fetch with two arguments, if you don’t care about your requestOptions argument then you can use expect.anything()
I am new to node.js.I am using await/async to avoid function to run before completing previous one.First of all here is code.
---------------first-----------
exports.createProfileUser = async (req, res, next) => {
const {user_image,image_two,
image_three,image_four,
image_five} = req.files
try{
var filetype = req.files.user_image.name.split(".");
var newFileName = "./public/images/"+Date.now()
+ Math.floor(100000 + Math.random() * 900000)
+ "."+filetype[1]
await insertImages(req,newFileName)
await createProfile(req,res,newFileName.substring(1), (result) =>{
if(result){
return res.json(result)
}
else{
return res.json({
status:false,
message:'Error Occurred '
})
}
})
. then((result) => {
if(result){
return res.json(result)
}
else{
return res.json({
status:false,
message:'Error Occurred '
})
}
})
}
catch(error){
res.sendStatus(500) && next(error)
}};
In above code i want insertImages function to be fully finished before calling createProfile.But that's not happening.Here is insertImages code.
--------------two--------------
insertImages = (req,baseFileName) =>{
const {user_id} = req.fields
var newFileNameTemp = baseFileName.substr(1);
if(image){
let fileType = req.files.image_five.name.split(".")
let name = "./public/images/"+Date.now() + "." + fileType[1]
let tempName = name.substr(1);
fs.copyFile(req.files.image_five.path,
name,
async(err) => {
if (err) {
console.log("Error in copying file",err)
return res.json({
status:false,
message:"Error occurred while updating Profile Pic Two of the user ",
})
}
await makeGallery(user_id,tempName, (resultId)=>{
console.log('resultId,',resultId)
})
});
}
}
After copying file i am saving a object in gallery schema and after that get its _id and update that to users schema.Code for that is.
--------------threee----------------
makeGallery = async (user_id,imageName,callback) => {
var g = new Gallery();
g.image = imageName
var saved = await g.save()
.then( async (gallery) => {
await Users.findOneAndUpdate({user_id: user_id},{$push: {gallery:[gallery._id]}},
{ upsert: true }
)
.then(async(data) =>{
await console.log("Successfully added");
})
await callback(gallery._id)
})
.catch(err => {
return {
status:false,
message:err.message,
}
});
}
I have used await so function will wait till data updates. But that's not working what i expected.createProfile function is called before insertImages is finished.What i am doing wrong here?Please correct my code i am stuck in this issue.Thanks in advance.
Mainly you are not synchronizing with fs.copyFile which is asynchronous
>>> insertImages = async (req,baseFileName) => {
const {user_id} = req.fields
var newFileNameTemp = baseFileName.substr(1);
if(image){
let fileType = req.files.image_five.name.split(".")
let name = "./public/images/"+Date.now() + "." + fileType[1]
let tempName = name.substr(1);
>>> await new Promise(function(resolve, reject){
>>> return fs.copyFile(req.files.image_five.path, name, err => {
if (err) {
console.log("Error in copying file",err)
// you should return the response server elsewhere. NOT in insertImages..
// you should throw a proper error as well
>>> return reject(res.json({
status:false, // should be 500 for internal server error
message:"Error occurred while updating Profile Pic Two of the user ",
}))
}
>>> return resolve()
})
})
}
await makeGallery(user_id,tempName, (resultId)=>{
console.log('resultId,',resultId)
})
}
Eventually, you may use
const copyFile = require('util').promisify(fs.copyFile)
so you can directly write
>>> insertImages = async (req,baseFileName) => {
const {user_id} = req.fields
var newFileNameTemp = baseFileName.substr(1);
if(image){
let fileType = req.files.image_five.name.split(".")
let name = "./public/images/"+Date.now() + "." + fileType[1]
let tempName = name.substr(1);
>>> await copyFile(req.files.image_five.path, name).catch(err => {
console.log("Error in copying file",err)
>>> throw res.json({
status:false,
message:"Error occurred while updating Profile Pic Two of the user ",
})
})
}
await makeGallery(user_id,tempName, (resultId)=>{
console.log('resultId,',resultId)
})
}
I am working on a site using Express.js, node.js, Axios, and ejs. I am making REST calls to a Oracle SQL REST services using Axios. I am having trouble working with Promises or Async/Await. I could use some guidance, if possible.
I have a repository layer to interface with the Oracle DB. For example:
dataaccess.js
const axios = require('axios');
exports.IsManufacturerCategory = function (categoryId) {
axios.get(`DB ADDRESS ${categoryId}`)
.then(response => {
console.error('GET IsManufacturerCategory categoryId = ' + categoryId);
console.error('Response = ' + JSON.stringify(response.data));
return (response.data);
})
.catch(rej => {
console.error('ERROR IsManufacturerCategory categoryId = ' + categoryId);
console.error('ERR = \n' + rej.data);
return (rej.data);
});
}
Which is called in my middleware. When I call var isManufacturerCat = exports.IsManufacturerCategory(categoryId); it is undefined. I am attempting to use the data retrieved from the Axios call to return a ejs view to my router, which I can provide if needed.
category.js
var isManufacturerCat = exports.IsManufacturerCategory(categoryId);
if (isManufacturerCat) {
var models = dataaccess.GetCategorySubCategories(categoryId);
return ("manufacturers", {
data: {
Canonical: cononical,
Category: category,
IsAManufacturerCategory: iAManufacturerCat,
Models: models
}
});
}
I am open to any advice in my project structure, usage of Promises, Async/Await, etc.
Thank you in advance.
EDIT
After working with some of the answers given, I have made some progress but I am having issues with layers of async calls. I end up getting into a spot where I need to await a call, but I am in a function that I am not able/do not want to do so (i.e. my router).
indexMiddleware.js
exports.getRedirectURL = async function (fullOrigionalpath) {
if (fullOrigionalpath.split('.').length == 1 || fullOrigionalpath.indexOf(".aspx") != -1) {
if (fullOrigionalpath.indexOf(".aspx") != -1) {
//some string stuff to get url
}
else if (fullOrigionalpath.indexOf("/solutions/") != -1) {
if (!fullOrigionalpath.match("/solutions/$")) {
if (fullOrigionalpath.indexOf("/t-") != -1) {
//some stuff
}
else {
var solPart = fullOrigionalpath.split("/solutions/");
solPart = solPart.filter(function (e) { return e });
if (solPart.length > 0) {
var solParts = solPart[solPart.length - 1].split("/");
solParts = solParts.filter(function (e) { return e });
if (solParts.length == 1) {
waitForRespose = true;
const isASolutionCategory = await dataaccess.isASolutionCategory(solParts[0]); // returns void
if (isASolutionCategory != undefined && isASolutionCategory.length > 0 && isASolutionCategory[0].Count == 1) {
// set redirecturl
}
}
else {
redirecturl = "/solutions/solutiontemplate";
}
}
}
}
}
else if (URL STUFF) {
// finally if none of the above fit into url condition then verify current url with Category URL or product url into database and if that matches then redirect to proper internal URL
if (fullOrigionalpath.lastIndexOf('/') == (fullOrigionalpath.length - 1)) {
fullOrigionalpath = fullOrigionalpath.substring(0, fullOrigionalpath.lastIndexOf('/'));
}
waitForRespose = true;
const originalURL = await exports.getOriginalUrl(fullOrigionalpath); //returns string
redirecturl = originalURL;
return redirecturl;
}
}
if (!waitForRespose) {
return redirecturl;
}
}
exports.getOriginalUrl = async function (friendlyUrl) {
var originalUrl = '';
var urlParts = friendlyUrl.split('/');
urlParts = urlParts.filter(function (e) { return e });
if (urlParts.length > 0) {
var skuID = urlParts[urlParts.length - 1];
const parts = await dataaccess.getFriendlyUrlParts(skuID); //returns void
console.log("Inside GetOriginalUrl (index.js middleware) FriendlyUrlParts: " + parts);//undefined
if (parts != undefined && parts != null && parts.length > 0) {
//some stuff
}
else {
// verify whether it's category URL then return the category local URL
console.log('Getting CategoryLocalUrl');
const categoryLocalUrl = await dataaccess.getCategoryLocalUrl(friendlyUrl); // returns void
console.log('CategoryLocalUrl Gotten ' + JSON.stringify(categoryLocalUrl)); //undefined
if (categoryLocalUrl != undefined && categoryLocalUrl.length > 0) {
//set originalUrl
return originalUrl;
}
}
}
else { return ''; }
}
index.js router
router.use(function (req, res, next) {
//bunch of stuff
index.getRedirectURL(url)
.then(res => {
req.url = res;
})
.catch(error => {
console.error(error);
})
.finally(final => {
next();
});
}
I am getting undefined in my console.logs after the awaits. I'm not really sure what I'm doing I guess.
Let's start with dataaccess.js. Basically, you're exporting a function that's doing async work, but the function isn't async. Most people want to be able to utilize async/await, so rather than have IsManufacturerCategory accept a callback function, it would better to have the function return a promise. The easiest way to do that is to make the function an async function. Async functions return promises which are resolved/rejected more easily than by returning an explicit promise. Here's how that could be rewritten:
const axios = require('axios');
exports.IsManufacturerCategory = async function (categoryId) {
try {
const response = await axios.get(`DB ADDRESS ${categoryId}`);
console.log('GET IsManufacturerCategory categoryId = ' + categoryId);
console.log('Response = ' + JSON.stringify(response.data));
} catch (err) {
console.error('ERROR IsManufacturerCategory categoryId = ' + categoryId);
console.error('ERR = \n' + rej.data);
throw err;
}
}
Note that I'm using console.error only for errors. Because you wanted to log some error related details, I used a try/catch statement. If you didn't care about doing that, the function could be simplified to this:
const axios = require('axios');
exports.IsManufacturerCategory = async function (categoryId) {
const response = await axios.get(`DB ADDRESS ${categoryId}`);
console.log('GET IsManufacturerCategory categoryId = ' + categoryId);
console.log('Response = ' + JSON.stringify(response.data));
}
This is because async functions automatically swallow errors and treat them as rejections - so the promise returned by IsManufacturerCategory would be rejected. Similarly, when an async function returns a value, the promise is resolved with the value returned.
Moving on to category.js... This looks strange because you're accessing IsManufacturerCategory from the exports of that module when I think you mean to access it from the import of the dataaccess module, right?
Inside this function, you should put any async work in an async function so that you can use await with function that return promises. Here's how it could be rewritten:
const dataaccess = require('dataccess.js');
async function validateManufacturerCat(categoryId) {
const isManufacturerCat = await dataaccess.IsManufacturerCategory(categoryId);
if (isManufacturerCat) {
const models = await dataaccess.GetCategorySubCategories(categoryId);
return ({
manufacturers: {
data: {
Canonical: cononical,
Category: category,
IsAManufacturerCategory: iAManufacturerCat,
Models: models
}
}
});
}
}
validateManufacturerCat(categoryId)
.then(res => {
console.log(res);
})
.catch(err => {
console.error(err);
});
A couple notes:
I changed the return value in the if statement to be a single value. You should try to always return a single value when working with promises and async/await (since you can only resolve/return one value).
I see lots of functions starting with capital letters. There's a convention in JavaScript where functions with capital letters are constructor functions (meant to be invoked with the new keyword).
Here is a working example. Note that you need a callback function to get the data when it is available from the promise
//client.js
const axios = require("axios")
exports.IsManufacturerCategory = function (url, callback) {
axios.get(url)
.then(response=>
{
callback(response.data);
})
.catch(error=>{
callback( error);
})
};
//app.js
const client = require('./client');
function process(data) {
console.log(data)
}
client.IsManufacturerCategory("http://localhost:3000/persons",process);
documentation
I am trying to write to a json file where I will re-read the file again after it has been written into. However, my console.log(readJson()); is showing me undefined when I try to re-read the file. Could anyone advise what I should do?
helper.js
const fs = require('fs')
const util = require('util');
const path = require('path')
const json_file = path.resolve(__dirname, "../json/metrics.json")
function readJson(){
fs.readFile(json_file,function(err,data){
if(err){
return console.error(err)
}
let iplist = data.toString()
iplist = JSON.parse(iplist)
let str = JSON.stringify(iplist)
return str
})
}
function writeJson(ipdetails){
fs.readFile(json_file,function(err,data){
if(err){
return console.error(err)
}
let iplist = data.toString()
iplist = JSON.parse(iplist)
iplist.table.push(ipdetails.data)
let str = JSON.stringify(iplist)
fs.writeFile(json_file,str,function(err){
if(err){
console.error(err);
}
console.log('returning readJson() below')
console.log(readJson());
})
})
}
module.exports = {
writeJson,
readJson
}
The return str is inside of the readFile callback you should either use promises or fs.readFileSync like this:
function readJson() {
let data = fs.readFileSync(json_file)
let iplist = data.toString()
iplist = JSON.parse(iplist)
let str = JSON.stringify(iplist)
return str
}
The async way is a little harder:
function readJson() {
new Promise((resolve, reject) =>
fs.readFile(json_file, type, (err, data) => {
let iplist = data.toString()
iplist = JSON.parse(iplist)
let str = JSON.stringify(iplist)
return err ? reject(err) : resolve(str);
})
);
}
You call the async verison like this:
readJson().then((result) => {
console.log(result)
})
async file example
Here is some information on async functions
Hopefully, this helps.
I am fetching playlistId from youtube api .
It gives correct output when console output within the youtube search function.
It gives undefined outside youtube search api function.
var playlistId;
async function suggestTrack(genre) {
youtube.search.list({
auth: config.youtube.key,
part: 'id,snippet',
q: genre
}, function (err, data) {
if (err) {
console.error('Error: ' + err);
}
if (data) {
console.log(data.items[0].id.playlistId); //getting the id
playlistId = data.items[0].id.playlistId;
}
//process.exit();
});
console.log(playlistId);// undefined
const tracks = await youtube_api.getPlaylistTracks(playlistId);
return tracks[Math.floor(tracks.length * Math.random())];
}
The API call is asynchronous. And you are printing the value of playlistId before the response of the api even comes back. You have to wait for the response to come. And since you are using async wrap the api call in a Promise and use await. To promisify the search.list method, you have a lot of options, or you can do it yourself, like below
function search(key, part, genre) {
return new Promise((resolve, reject) => {
youtube.search.list({
auth: key,
part: part,
q: genre
}, function (err, data) {
if (err) {
reject(err);
return;
}
// use better check for playlistId here
resolve(data ? data.items[0].id.playlistId : null);
})
});
}
// then use it here
async function suggestTrack(genre) {
const playlistId = await search(config.youtube.key, 'id,snippet', genre);
const tracks = await youtube_api.getPlaylistTracks(playlistId);
return tracks[Math.floor(tracks.length * Math.random())];
}
youtube.search.list is asynchronous. You are trying to access to playlistId as it was a part of a synchronous process.
You can wrap the youtube.search.list inside a Promise to simplify it's use.
OLD WAY
function wrappedSearch() {
return new Promise((resolve, reject) => {
youtube.search.list({
auth: config.youtube.key,
part: 'id,snippet',
q: genre
}, (err, data) => {
if (err) {
console.error('Error: ' + err);
return reject(err);
}
return resolve((data && data.items[0].id.playlistId) || false);
});
});
}
async function suggestTrack(genre) {
const playlistId = await wrappedSearch();
// Here playlistId is either the playlistId, either false
console.log(playlistId);
const tracks = await youtube_api.getPlaylistTracks(playlistId);
return tracks[Math.floor(tracks.length * Math.random())];
}
NEW WAY
available in node v8 doc
tutorial
const {
promisify,
} = require('util');
const youtubeSearchAsync = promisify(youtube.search.list);
async function suggestTrack(genre) {
const data = await youtubeSearchAsync({
auth: config.youtube.key,
part: 'id,snippet',
q: genre
});
const playlistId = (data && data.items[0].id.playlistId) || false;
console.log(playlistId);
const tracks = await youtube_api.getPlaylistTracks(playlistId);
return tracks[Math.floor(tracks.length * Math.random())];
}