handling multiple errors in Node js - javascript

I have a method in Node JS which reads a file containing JSON data and finds a product with specific ID.
async getProductwithId(id) {
try {
let rawData = fs.readFileSync("data/products.json");
let data = JSON.parse(rawData);
for (const element of data) {
if (id === element.productId) {
return element;
}
}
throw new ProductDoesNotExistError("No Such Product Exists");
} catch (error) {
throw new FileReadingError("Error Reading File");
}
}
where ProductDoesNotExistError and FileReadingError both extend Error. I have put try/catch for the fs.readFileSync()
the problem is even if i have ProductDoesNotExistError, it's sending FileReadingError. I want to handle here the FileReadingError only and not ProductDoesNotExistError. I will let the callling function handle the ProductDoesNotExistError. How do I achieve this functionality.

Since in your catch block you throw a new instance of FileReadingError, all caught errors will result in the latter. You could either put the try/catch just around the readFileSync operation or check the type of the error in your catch block (also there's no need for async as the code inside the method is not async - e.g. your not using fs.promises.readFile()):
getProductwithId(id) {
let rawData;
try {
rawData = fs.readFileSync("data/products.json");
} catch (error) {
throw new FileReadingError("Error Reading File");
}
const data = JSON.parse(rawData);
for (const element of data) {
if (id === element.productId) {
return element;
}
}
throw new ProductDoesNotExistError("No Such Product Exists");
}
or you do:
getProductwithId(id) {
try {
const rawData = fs.readFileSync("data/products.json");
const data = JSON.parse(rawData);
for (const element of data) {
if (id === element.productId) {
return element;
}
}
throw new ProductDoesNotExistError("No Such Product Exists");
} catch (error) {
if (error instanceof ProductDoesNotExistError) {
// rethrow ProductDoesNotExistError error
throw error;
}
throw new FileReadingError("Error Reading File");
}
}

Related

issue in identifying whether the zip file is password protected using javascript

I have a simple web application for uploading zip files to a server. In the Javascript part I have used a try-catch block for checking whether the files are password protected(A predefined and known password) by reading the entries and catching the corresponding error.
The js library which I am using is https://github.com/gildas-lormeau/zip.js/blob/master/dist/zip.min.js.
let reader;
try {
reader = new zip.ZipReader(new zip.BlobReader(file), {
password
});
const entries = await reader.getEntries();
for (const entry of entries) {
try {
await entry.getData(new zip.BlobWriter(), {
onprogress: (index, max) => {
zip.BlobWriter.$cancel()
reader.close()
}
});
} catch (error) {
if (error.message === zip.ERR_ENCRYPTED ||
error.message === zip.ERR_INVALID_PASSWORD) {
alert("Incorrect password")
return false;
} else {
console.log(error)
}
}
}
} catch (error) {
console.log(error)
} finally {
await reader.close();
}
The above code successfully finds out if the file is not encrypted by the predetermined password. However, for some files the error statement is as below.
TypeError: Cannot read properties of undefined (reading 'importKey')
I would like to know why this happens and how to know whether the file is password protected or not.
Thank You
There are some issues with the code you proposed, for example BlobWriter.$cancel is not documented anywhere and does not exist actually. Also, you should call reader.close() only once.
Here is below how such a function could be written.
const verifyZipPassword = async (file, password) => {
const reader = new zip.ZipReader(new zip.BlobReader(file), { password });
const entries = await reader.getEntries();
try {
for (const entry of entries) {
const abortController = new AbortController();
const signal = abortController.signal;
const onprogress = () => abortController.abort();
await entry.getData(new zip.BlobWriter(), { signal, onprogress });
}
} catch (error) {
if (error.message == zip.ERR_INVALID_PASSWORD) {
return false;
} else if (error.message != zip.ERR_ABORT) {
throw error;
}
} finally {
await reader.close();
}
return true;
};

how to return a newly created object when using sequelize transcation?

I have a following function, which works, when passed a new user data . it saves the object and the child object into the mysql table successfully. but how do i return the object back , once saved to the database, given i'm using sequelize transaction.
static async add(user) {
let transaction;
try {
// get transaction
transaction = await models.sequelize.transaction();
// *****how to return the newly created user *****************************************
models.User.create(user).then(newUser => {
const id = newUser.id;
//save address
if(user.address){
address.userId = id;
models.Address.create(address);
}
}).catch(error => {
throw error;
});
await transaction.commit();
} catch (error) {
console.log(error);
// Rollback transaction
if (transaction) await transaction.rollback();
throw error;
}
}
Try to create an auto-transaction, use await and indicate transaction in models's create functions:
static async add(user) {
try {
const createdUser = await models.sequelize.transaction(transaction => {
const newUser = await models.User.create(user, { transaction })
//save address
if(user.address){
address.userId = newUser.id;
await models.Address.create(address, { transaction });
}
return newUser;
});
// if you are here it means transaction already commited
return createdUser;
} catch (error) {
// if you are here it means transaction already rolled back
console.log(error);
throw error;
}
}

Promise returning undefined result to callback

I'm having issues with getting the result of a callback function. Below is the async function that I'm calling
const utils = {
sendQuery: async function(query){
// Receives a query and returns raw results
// Query is using default database specified by pool
// Returns a Promise
let conn;
try {
conn = await pool.getConnection();
let queryString = query;
let rows = await conn.query(queryString);
let results = (this.formatResults(rows));
console.log(results);
return results;
} catch(err) {
throw new Error(err);
} finally {
if (conn) return conn.end();
}
}
module.exports = {
'utils': utils
}
the console log above returns the expected result.
and below is the function that calls the above
const db = require('../private/db');
db.utils.sendQuery(queryString).then(function(result){
console.log(result);
}).catch(err=>{
throw res.render('error', {'error': err.stack});
})
the console log above returns undefined and I have no idea why.
The real problem here is this part if (conn) return conn.end();.
Whenever you are using finally, it will override any previous return, break, continue or throw that happens either in the stated try or catch blocks.
To fix your issue you should do like so:
const utils = {
sendQuery: async function(query){
// Receives a query and returns raw results
// Query is using default database specified by pool
// Returns a Promise
let conn;
try {
conn = await pool.getConnection();
let queryString = query;
let rows = await conn.query(queryString);
let results = (this.formatResults(rows));
console.log(results);
return results;
} catch(err) {
throw new Error(err);
} finally {
if (conn) conn.end();
}
}
module.exports = {
'utils': utils
}
Hope it works
In my opinion, just return results instead of resolve(results). Your function is already async and no promise object is created here.
And just throw err instead of reject(err);
And since you return in your try, you don't need your finally statement.
You need to simply return the result instead of calling resolve
const utils = {
sendQuery: async function(query){
// Receives a query and returns raw results
// Query is using default database specified by pool
// Returns a Promise
let conn;
try {
conn = await pool.getConnection();
let queryString = query;
let rows = await conn.query(queryString);
let results = (this.formatResults(rows));
console.log(results);
return results;
} catch(err) {
throw new Error(err)
} finally {
if (conn) return conn.end();
}
}
module.exports = {
'utils': utils
}
you could simply return or i suppose this is what you were trying to do
sendQuery: (query) => {
let promise = new Promise(async (resolve, reject) => {
let conn;
try {
conn = await pool.getConnection();
let queryString = query;
let rows = await conn.query(queryString);
let results = (this.formatResults(rows));
console.log(results);
resolve(results);
} catch (err) {
reject(err);
} finally {
if (conn) {
conn.end();
}
}
})
return promise;
}

Log time taken to execute aync await function

How can I find how much time this function takes to execute?
export async function queryElasticSearch(userQuery, index) {
if (_.isEmpty(userQuery)) {
throw new Error('User query is empty or null');
}
try {
const elasticSearchRequestBody = getElasticSearchRequestBody(index, userQuery);
return await elasticSearchClient.search(elasticSearchRequestBody);
} catch (err) {
throw err;
}
}
Something like this:
export async function queryElasticSearch(userQuery, index) {
const start = Date.now()
try {
if (_.isEmpty(userQuery)) throw new Error('User query is empty or null');
const elasticSearchRequestBody = getElasticSearchRequestBody(index, userQuery);
return await elasticSearchClient.search(elasticSearchRequestBody);
} finally {
console.log(Date.now() - start)
}
}
Or alternatively, you can use performance.now() if you want precision in microseconds...
Edit: added finally per Bergi suggestion.
you can also implement this with console.time ie
export async function queryElasticSearch(userQuery, index) {
console.time('time');
try {
if (_.isEmpty(userQuery)) throw new Error('User query is empty or null');
const elasticSearchRequestBody = getElasticSearchRequestBody(index, userQuery);
return await elasticSearchClient.search(elasticSearchRequestBody);
} finally {
console.timeEnd('time')
}
}

Jest TypeError: function not found

I am trying to run a test with jest, except it cannot find my function. I am exporting multiple functions from one file using module.exports = {}.
Here is my test file:
const queries = ('../config/queries');
test('Check Activation Code. -- checkActivationCode(test#gmail.com, 0123456789) ', () => {
let email = 'test%40gmail.com';
let code = 1234567890;
let result = "";
queries.checkActivationCode(email, code, function(error, result) {
if (error) result = false;
else result = true;
});
expect(result).toBe(true);
});
My file structure is as follows, /config/queries/index.js, I am able to access the functions in my other files just fine.
Here is my queries/index.js file:
module.exports = {
checkActivationCode: function(email, code, callback) {
pool.getConnection(function(error, connection) {
connection.query('SELECT code FROM confirmation WHERE email = ?', [email.toLowerCase()], function(error, results) {
if (error) callback(error);
try {
if (results[0].code === code) {
callback(null, true);
} else {
callback(null, false);
}
} catch (e) {
callback(null, false);
}
});
connection.release();
});
}
}
I forgot to require my queries.
const queries = ('../config/queries');
to
const queries = require('../config/queries');
Simple typo. Thanks #BenceGedai for catching that.

Categories

Resources