I'm using the sqlite3 package in node and beginning to flush out my REST API. I've decided to create a promise wrapper around the DB calls and in the controllers, use async/await to call those functions and set that return value to a variable. Then, check the variable and set a response object. For the success cases it's working well, found a thing and set the response. Problem is, in SQLITE3 I'm having a hard time checking for errors. I have a basic check for undefined in the DB service which does throw an error if it encounters an error, but that error goes immediately to the CATCH section of the controller and doesn't allow me to wrap it in an API response I'd like to define. These are separate files (controller vs. service). I'm not finding a lot of helpful information on error checking for sqlite3, it's sparse out there. Ideally the service would throw an error which I could then wrap into a standardized response object and send.
------ LOCATION
const getById = async (req, res, next) => {
response = {};
try {
let location = await getLocationById(req.params.id); // <-- IF NO VALUE FOUND, location IS nothing
if (error) { // <----- THIS IS WHERE I'D LIKE TO CHECK FOR ERRORS.
response.status = 404;
response.message = 'Error attempting to get location';
} else {
response.status = 200;
response.message = 'Success';
response.data = location;
}
res.json(response);
} catch (error) {
res.json(response);
}
};
------------ SERVICE
const getLocationById = (id) => {
return new Promise((resolve, reject) => {
let sql = 'SELECT * FROM Locations WHERE id = ?;';
db.get(sql, [id], (error, location) => {
if (location !== undefined) {
resolve(location);
} else {
reject(new Error('Error attempting to get location by id'));
}
});
});
};
You just need to wrap the call to getLocationById()
in another try/catch
. From there you can decide if you want to wrap or raise the error. If you don't have additional code to add that might throw an error you can remove the outer try/catch
. More explanation and suggestions in inline comments:
const getLocationById = (id) => {
return new Promise((resolve, reject) => {
const sql = "SELECT * FROM Locations WHERE id = ?;";
db.get(sql, [id], (error, location) => {
// check for an error from the db here
if (error) return reject(error);
// check for an empty result here and throw your own error
if (!location) {
// set a property so we can tell that it wasn't a db error just not found
const myError = new Error("Error attempting to get location by id");
myError.notFound = true;
return reject(myError);
}
// otherwise resolve the result
return resolve(location);
});
});
};
const getById = async (req, res, next) => {
// use const since it is not reassigned, only properties are changed
const response = {};
try {
// code here that might throw an exception
try {
// use const if you aren't going to reassign `location`
const location = await getLocationById(req.params.id);
// we were able to load the location if we get here
response.status = 200;
response.message = "Success";
response.data = location;
} catch (error) {
// maybe check to see if we want to wrap or raise the error
// maybe call console.log(error) to see the contents
const doWeWantToWrapTheError = somethingToCheckTypeEtc(error);
if (doWeWantToWrapTheError) {
if (error.notFound) {
// no db errors, just not found
response.status = 404;
} else {
// some kind of db error so set to "internal server error"
response.status = 500;
}
response.message = "Error attempting to get location";
} else {
// raise the error to the outer try/catch
throw error;
}
}
// code here that might throw an exception
return res.json(response);
} catch (unexpected) {
// some other error occurred that was not caught above (unlikely)
// maybe call console.log(unexpected) to see the contents
response.error = unexpected.message;
return res.json(response);
}
};