I am new to javascript world and my first project was to create an efficient MSSQL rest API using Express. I started by studying a few basic examples and I ended up with this which is working fine:
const utils = require('../utils');
const config = require('../../config');
const sql = require('mssql');
const getEvents = async () => {
try {
let pool = await sql.connect(config.sql);
const sqlQueries = await utils.loadSqlQueries('events');
const eventsList = await pool.request().query(sqlQueries.eventslist);
console.log(eventsList);
return eventsList.recordset;
} catch (error) {
console.log(error.message);
}
}
module.exports {getEvents};
I am using a separate js file to handle my routes, a config file to handle my .env variables an eventController.js to handle the events (like the get events) and also a utils file to handle my sql queries.
index.js
const express = require('express');
const config = require('./config');
const cors = require('cors');
const bodyParser = require('body-parser');
const eventRoutes = require('./routes/eventRoutes');
const app = express();
app.use(express.json());
app.use(cors());
app.use(bodyParser.json());
app.use('/api', eventRoutes.routes);
app.listen(config.port, () => {
console.log('Server is listening on ' + config.url)
}).on('error', (e) => {
console.log('Error starting the server', e.message)
});
config.js
const dotenv = require('dotenv');
const assert = require('assert');
dotenv.config();
const { PORT, HOST, HOST_URL, SQL_USER, SQL_PASSWORD, SQL_SERVER, SQL_DATABASE } = process.env;
const sqlEncrypt = process.env.ENCRYPT === true;
assert(PORT, 'PORT is required');
assert(HOST, 'HOST is requred');
module.exports = {
port: PORT,
host: HOST,
url: HOST_URL,
sql: {
server: SQL_SERVER,
database: SQL_DATABASE,
user: SQL_USER,
password: SQL_PASSWORD,
options: {
encrypt: sqlEncrypt,
enableArithAbort: true
},
},
};
routes.js
const express = require('express');
const eventControler = require('../controllers/eventController');
const router = express.Router();
const { getEvents, getEvent, addEvent, updateEvent, deleteEvent } = eventControler;
router.get('/events', getEvents);
router.get('/event/:id', getEvent);
router.post('/event', addEvent);
router.put('event/:id', updateEvent);
router.delete('/event/:id', deleteEvent);
module.exports = {
routes: router
}
eventsController.js
const eventData = require('../data/events');
const getAllEvents = async (req, res, next) => {
try {
const eventlist = await eventData.getEvents();
res.send(eventlist);
} catch (error) {
res.status(400).send(error.message);
}
}
module.exports {getEvents};
I am also using a utils.js file to convert my.sql files to sql queries nothing too fancy there I am sure most of you are aware of this function as its widely used. Now, although the API works as intended I wanted to fine-tune connection pool management a bit to avoid the occasion of the server making new pools for each user request and also for debugging and state monitoring reasons, so having studied a lot of issues here I decided to introduce a new file called client.js:
const sql = require("mssql");
const config = require("../config");
const client = new sql.ConnectionPool(config.sql)
.connect()
.then(pool => {
console.log('connected to MSSQL server')
return pool
})
.catch(err => console.log('Database connection failed! Bad config: ', err))
module.exports = {
sql,
client
};
and then I modified my getEvents function like this:
const getEvents = async () => {
try {
const pool = await client;
const sqlQueries = await utils.loadSqlQueries('events');
const list = await pool.request().query(sqlQueries.eventsList);
console.log(list);
return list.recordset;
} catch (error) {
return error.message;
}
}
I am getting a 200 response but the body is empty and the recordset is undefined. I also tried the approach described here: pool.request is not a function
modifying my client.js to:
const sql = require("mssql");
const config = require("../config");
const client = new sql.ConnectionPool(config.sql);
const poolConnection = client.connect()
.then(pool => {
console.log('connected to MSSQL server')
return pool
})
.catch(err => console.log('Database connection failed! Bad config: ', err))
module.exports = {
poolConnection,
client
};
and I also modified my getEvents.js to:
const config = require('../../config');
const sql = require('mssql');
const {poolConnection, client} = require('./client');
const getEvents = async () => {
await poolConnection;
try {
const sqlQueries = await utils.loadSqlQueries('events');
const eventsList = await client.request().query(sqlQueries.eventslist);
console.log(eventsList);
return eventsList.recordset;
} catch (error) {
console.log(error.message);
}
}
module.exports {getEvents};
But I didn't get any luck with either. The response is 200 still but the recordset is undefined. What am I missing here?
Could you please point me to the right direction as to how I can use the global pool efficiently and not flood the sql server with new connection requests ?