Can't get Node mssql to work properly - javascript

This is the way I'm using mssql at the moment but it gives sometimes errors:
JavaScript:
router.get('/academiejaren', (req, res) => {
sql.connect(dbconfig, function (err) {
var request = new sql.Request();
if (err) {
console.log(err);
return;
}
request.query("SELECT * FROM [Alg].[DefAJ];", function (err, recordset) {
if (err) {
console.log(err);
return;
}
else {
res.end(JSON.stringify(recordset));
}
});
request.query();
});
});
Error:
{ ConnectionError: Connection is closed.
at C:\Users\Milan\Documents\Octopus\Octopus 2.0\node_modules\mssql\lib\main.js:1569:17
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickCallback (internal/process/next_tick.js:104:9)
name: 'ConnectionError',
message: 'Connection is closed.',
code: 'ECONNCLOSED' }
(node:556) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ConnectionError: Connection is closed.
(node:556) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I'm using version 3.2.0 because I can't get the newest one, 4.0.2, to work... Any help or some good examples, because I can't figure out the documentation...
thank in advance!
EDIT
Updated on a small test project to 4.0.2. and I got it to work. Going to change my API to this update.
router.get('/academiejaren', (req, res) => {
(async function () {
try {
let pool = await sql.connect(config)
let result1 = await pool.request()
.query('SELECT * FROM [Alg].[DefAJ];')
res.send(JSON.stringify(result1.recordset));
} catch (err) {
res.send("CAUGHT ERROR academiejaren");
}
})()
sql.on('error', err => {
// ... error handler
})
});
Now I do have a small question left, what should I do with the catch and sql.on()? How should I handle error's?

router.get('/academiejaren', (req, res) => {
sql.connect(dbconfig, function (err) {
var request = new sql.Request();
if (err) {
console.log(err);
return;
}
request.query("SELECT * FROM [Alg].[DefAJ];", function (err, recordset) {
if (err) {
console.log(err);
return;
}
else {
res.send(JSON.stringify(recordset));
}
});
request.query();
});
});
you literally did res.end, end exits it, you want res.send

I do it a little bit different:
router.get('/', function(req, res, next) {
sql.connect(dbconfig).then(function() {
// Query
new sql.Request().query("Your query")
.then(function(recordset) {
//console.dir(recordset);
res.setHeader('Content-Type', 'application/json');
res.send( recordset );
}).catch(function(err) {
// ... query error checks
});
});
});
Now in your dbconfig make sure you got it like:
mssql://user:password#server/db

Related

Global connection already exists despite sql.close()

I created query function to connect to mssql database like below:
query(query) {
return sql.connect(config.connection.sqlserver).then(() => sql.query(query)).then((result) => {
sql.close();
return result.recordset;
}).catch((err) => console.log(err));
},
When I'm starting nodejs server everything works fine. When I'm doing refresh many times I'm getting result from database e.g.
But when I'm sending request from client side to server side I'm getting an error like below:
(node:19724) UnhandledPromiseRejectionWarning: Error: Global connection already
exists. Call sql.close() first.
at Object.connect (C:\repos\mtg-app\node_modules\mssql\lib\base.js:1723:31)
at query (C:\repos\mtg-app\server\query.js:6:16)
at asyncCall (C:\repos\mtg-app\server\routes\index.js:19:11)
at router.get (C:\repos\mtg-app\server\routes\index.js:29:3)
at Layer.handle [as handle_request] (C:\repos\mtg-app\node_modules\express\l
ib\router\layer.js:95:5)
at next (C:\repos\mtg-app\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\repos\mtg-app\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\repos\mtg-app\node_modules\express\lib\router\layer.js:95:5)
at C:\repos\mtg-app\node_modules\express\lib\router\index.js:281:22
at Function.process_params (C:\repos\mtg-app\node_modules\express\lib\router\index.js:335:12)
(node:19724) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:19724) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I don't understand first of all why it's working only on server and secondly why it's not working despite sql.close() method?
Please explain me this issue very well.
In regards to my comment, something along these lines.
async function query(q) {
return new Promise((resolve, reject) => {
new sql.ConnectionPool({/* Config */}).connect().then((pool) => {
return pool.request().query(q)
}).then((result) => {
// Resolve result
resolve(result);
// Close sql.close();
sql.close();
}).catch((error) => {
// Reject error
reject(error);
// Close sql.close();
sql.close();
});
});
}
query(`SELECT * FROM`)
.then((response) => {
// Success
console.log(response);
})
.catch((error) => {
// Error
console.log(error);
})
.finally(() => {
// Clean-up
});
Or another way, with mysqlijs all from the documentation here.
const mysql = require('mysql');
const pool = mysql.createPool({/* Config */});
pool.getConnection(function(error, connection) {
if (error) {
throw error;
}
// Use the connection
connection.query(`SELECT * FROM`, function (error, results, fields) {
// When done with the connection, release it.
connection.release();
// Handle error after the release.
if (error) throw error;
// Don't use the connection here, it has been returned to the pool.
});
});
pool.on('acquire', function (connection) {
console.log('Connection %d acquired', connection.threadId);
});
pool.on('enqueue', function () {
console.log('Waiting for available connection slot');
});
pool.on('release', function (connection) {
console.log('Connection %d released', connection.threadId);
});
pool.end(function (err) {
// Ending all connection the the MySQL pool.
});
I did it in the simpler way than below. But thanks Raymond because I realized that I should use ConnectionPool.
My query module:
/* eslint-disable import/no-unresolved */
const mssql = require('mssql');
const database = require('./config/connection');
const pool = new mssql.ConnectionPool(database.config).connect();
async function query(sql) {
try {
const connection = await pool;
const result = await connection.query(sql);
return result.recordset;
} catch (err) {
console.log('SQL error', err);
}
return [];
}
module.exports.query = query;
Now when I want to use it e.g. in router module:
router.get('/get-users', (req, res, next) => {
const usersStandings = [];
sql.query('select u.name, s.points from dbo.[user] u join dbo.standings s on s.id = u.standings_id join dbo.category c on c.id = s.category_id where c.type = \'Tournament\' order by points desc').then((rows) => {
rows.forEach((element) => {
usersStandings.push(element);
});
res.send(usersStandings);
});
});
Now I don't have problems with Global connection etc.

Error handling with deeply nested async functions

I'm having issues catching error when the functions are nested three levels deep. Here is a router with async functions:
router.post('/',
validatevalues,
async (req, res) => {
// if values are invalid then
// return res.status(422).send(errors.msg);
const result = await userController.post(req.body);
return res.status(201).send('Success');
},
);
const userController = {
async post(req) {
try {
await bcrypt.genSalt()
await bcrypt.hash();
await db.query(req.somevalues);
} catch (err) {
console.error(err);
};
};
};
const query = {
return new Promise(function(resolve, reject) {
...
if (err) {
reject(new Error(err));
} else {
resolve(res);
};
};
};
The console.error(err) is printing this stack trace
Error: error: duplicate key value violates unique constraint...
And then I get Uncaught AssertionError at the router level with Mocha testing:
Uncaught AssertionError: expected { Object (_events, _eventsCount, ...) } to have status code 422 but got 201
This seems expected since I am just console.error instead of throwing another newError at the controller level, but what do I need to do? If I throw another error, then wouldn't the stack trace be Error: error: error ...? This doesn't seem right to me.
You should only catch at the highest level:
router.post('/', validatevalues, async (req, res) => {
try {
const result = await userController.post(req.body);
return res.status(201).send('Success');
} catch(error) {
res.status(402).send(error.message);
}
});
If you still want to log at a lower level, you can rethrow the error:
} catch (err) {
console.error(err);
throw err;
} // no semicolon here, its unneccessary

How to catch the exception in the right way? [beginner]

There is the following function, which doesn't catch MyException.
const myFunction = () => async (req, res, next) => {
try {
myHTTPRequest().then(async (response) => {
if (response.data.results.length != 1) {
throw new MyException('MyError');
}
res.end('All good');
})
.catch((error) => {
throw error; //Doesn't work
});
} catch (error) {
console.log('This block should catch MyException, but it doesn't');
next(error);
}
};
Instead, the application writes following error message into the console
(node:45746) UnhandledPromiseRejectionWarning
(node:45746) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:45746) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
The question is, how does the code need to be adjusted to catch MyException in the expected Catch-Block?
The issue is that you're mixing .then/.catch with try/catch.
If you want the code to enter the try/catch in an async function, you have to use the await keyword on the Promise.
You can drop the .catch since it's doing nothing, you're throwing again the error, and that's causing the UnhandledPromiseRejectionWarning
const myFunction = () => (req, res, next) => {
try {
const response = await myHTTPRequest();
if (response.data.results.length != 1) {
throw new MyException('MyError');
}
res.end('All good');
} catch (error) {
next(error);
}
};
Using .then/catch without async/await the code would be:
const myFunction = () => (req, res, next) => {
myHTTPRequest().then((response) => {
if (response.data.results.length != 1) {
throw new MyException('MyError');
}
res.end('All good');
})
.catch((error) => {
throw error;
// It makes no sense to throw again in here
// But I'm showing you how to handle it if you do
})
.catch(error => {
next(error);
})
};
Of course the double .catch doesn't make sense, and you should remove it, leaving a single one:
const myFunction = () => (req, res, next) => {
myHTTPRequest().then((response) => {
if (response.data.results.length != 1) {
throw new MyException('MyError');
}
res.end('All good');
})
.catch(error => {
next(error);
})
};

UnhandledPromiseRejectionWarning in Express App

I'm currently learning Javascript/Node.js/MEAN stack and I'm following an Express tutorial.
I get the following error:
(node:11524) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'close' of undefined
(node:11524) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
When I hit this route in my browser.
function router(nav) {
adminRouter.route('/')
.get((req, res) => {
const url = 'mongodb://localhost:27017';
const dbName = 'libraryApp';
(async function mongo() {
let client;
try {
client = await mongoClient.connect(url);
debug('Connected correctly to server');
const db = client.db(dbName);
const response = await db.collection('books').insertMany(books);
res.json(response);
} catch (err) {
debug(err.stack);
}
client.close();
}());
});
return adminRouter;
}
Could someone point out the issue and explain what the issue is please.
If this line rejects:
client = await mongoClient.connect(url);
Then, you go to your catch block and after that catch block, you call client.close(). But, client is undefined so client.close() will throw and you are not inside any sort of try/catch at that point. Since you're inside an async function, that throw will turn into a rejected promise which you have no .catch() to handle. Thus, you end up with an unhandled promise rejection.
You should be able to fix it like this:
function router(nav) {
adminRouter.route('/').get(async (req, res) => {
const url = 'mongodb://localhost:27017';
const dbName = 'libraryApp';
let client;
try {
client = await mongoClient.connect(url);
debug('Connected correctly to server');
const db = client.db(dbName);
const response = await db.collection('books').insertMany(books);
res.json(response);
} catch (err) {
debug(err.stack);
// make sure and send some response on errors
res.sendStatus(500);
}
if (client) {
client.close();
}
});
return adminRouter;
}
This makes several changes:
Add if (client) before calling client.close() to protect it from the case where `client never got set.
Make the whole .get() callback be async rather then using an IIFE (not required, just seems cleaner to me)
Send an error status and response in your catch statement so you are always sending an http response of some kind, even in error situations.
If you really wanted to be fail-safe, you could just add another try/catch:
function router(nav) {
adminRouter.route('/').get(async (req, res) => {
const url = 'mongodb://localhost:27017';
const dbName = 'libraryApp';
let client;
try {
client = await mongoClient.connect(url);
debug('Connected correctly to server');
const db = client.db(dbName);
const response = await db.collection('books').insertMany(books);
res.json(response);
} catch (err) {
debug(err.stack);
// make sure and send some response on errors
res.sendStatus(500);
}
try {
if (client) {
client.close();
}
} catch(e) {
console.log("unable to close database connection");
}
});
return adminRouter;
}

How to throw exception for sync callback in nodejs?

I want to throw an error exception for an redis.set callback and catch in try-catch block and then get control to error handling express middleware.
try {
redis.get('key', (err, reply) => {
if(err) throw err;
if(!reply) throw new Error('Can't find key');
});
}
catch{
next(error);
}
the problem is, that try-catch is simply not working, error is going to node console, but server is responding with 200 status.
You cant catch async events. Use promises for that:
const getKey = new Promise((res,rej) => {
redis.get('key', (err, reply) => {
if(err) return rej(err);
res(reply);
});
});
So one can do:
getKey.catch(next);
getKey.then(reply => {
//do whatever
next();
});

Categories

Resources