I tried to connect oracle database to my project. I used the createpool in order to call this function in the future for all the necessary requests from the database. my config.js file:
const oracledb = require('oracledb')
oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT
const init = async function (query) {
try {
await oracledb.createPool({
user: 'almat',
password: 'almat789456123',
connectString: '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=xepdb1)))'
})
console.log('Connection pool started')
await dostuff(query)
} catch (err) {
console.error('init() error: ' + err.message)
} finally {
// await closePoolAndExit()
}
}
async function dostuff (query) {
let connection
try {
connection = await oracledb.getConnection()
const sql = query
const binds = [1]
const options = { outFormat: oracledb.OUT_FORMAT_OBJECT }
const result = await connection.execute(sql, binds, options)
console.log(result)
} catch (err) {
console.error(err)
} finally {
if (connection) {
try {
await connection.close()
} catch (err) {
console.error(err)
}
}
}
}
async function closePoolAndExit () {
console.log('\nTerminating')
try {
await oracledb.getPool().close(10)
console.log('Pool closed')
process.exit(0)
} catch (err) {
console.error(err.message)
process.exit(1)
}
}
process
.once('SIGTERM', closePoolAndExit)
.once('SIGINT', closePoolAndExit)
module.exports.init = init
My app.js file:
const express = require('express');
const config = require('./utils/config');
const app = express();
app.listen(3000, function () {
console.log('Server running at port 3000')
})
app.set('view engine', 'ejs')
app.get('/', function (req, res) {
return res.render('index')
})
app.get('/login', function (req, res) {
return res.render('login')
})
app.get('/getCustomerName', function (req, res) {
const query = 'SELECT firstname FROM customer WHERE :b = 1'
const result = config.init(query)
//console.log(typeof result)
return res.send(result)
})
module.exports = app
When I request http://localhost:3000/getCustomerName it returns empty json file and terminal throws this error: NJS-047: poolAlias "default" not found in the connection pool cache
The createPool() call should be run once during app initialization, eg around the time you call express(). From the createPool() doc:
This method creates a pool of connections with the specified user name, password and connection string. A pool is typically created once during application initialization.
init() shouldn't call doStuff(). Once the pool is created, then your web listener handlers can call dostuff().
Look at the basic example webapp.js.
Also see the Oracle Magazine series Build REST APIs for Node.js which has source code here.
Related
I would like to configure my project in order to run unit test for some API endpoints (that call the database). I'm using :
ExpressJS
MongoDB (no Mongoose)
Mocha / Chai
Mongodb Memory Server (to mock the DB)
// app.ts
export const app = express();
const port = process.env.PORT;
app.use("/my-route", myRoutes);
mongoConnect().then(() => {
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
});
// database.ts
export const mongoConnect = async () => {
try {
let MONGODB_URI = process.env.MONGODB_URI;
if (process.env.NODE_ENV === "test") {
const mongoServer = await MongoMemoryServer.create();
MONGODB_URI = mongoServer.getUri();
}
const client: MongoClient = await MongoClient.connect(MONGODB_URI);
_db = client.db("dbName");
_mongoClient = client;
if (process.env.NODE_ENV === "test") {
console.log("Connected to MongoDB Test");
} else {
console.log("Connected to MongoDB");
}
} catch (err) {
console.log("Error connecting to MongoDB:", err);
throw err;
}
};
export const getMongoClient = () => {
if (_mongoClient) {
return _mongoClient;
}
throw "Mongo client doesn't exist";
};
export const getDb = () => {
if (_db) {
return _db;
}
throw "No database found!";
};
// test.ts
let mongoClient: MongoClient;
let db: Db;
before(function (done) {
mongoConnect()
.then(() => {
db = getDb();
mongoClient = getMongoClient();
return db.createCollection("wordsCollection");
})
.then(() => {
db.collection("wordsCollection").insertMany(data);
})
.catch((err) => console.log(err))
.finally(() => done());
});
after(function (done) {
db.dropDatabase();
mongoClient.close().then(() => {
done();
});
});
it("test", async function () {
let res = await chai
.request(app)
.post("/my-route/hello")
.send({ excludeIds: [] });
expect(res.status).to.equal(200);
});
});
But it's not working...
If I call mongoConnect() in test.ts it console.log twice Connected to MongoDB Test. But if I don't call the function it throws me error because MongoClient is undefined.
I think await chai.request(app) already calls the database and server but I need to create Collection and Documents before. So I need to connect to the DB before the test.
Any help would be greatly appreciated.
I found a solution, I don't know if it's best practice but it works and is pretty easy, thanks to this post : https://stackoverflow.com/a/70285190/10547153.
I needed to add a condition in app.ts before making the connection to the database and the server in order to launch them only if it's called by Node itself.
if (require.main === module) {
mongoConnect().then(() => {
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
});
}
When a file is run directly from Node.js, require.main is set to its
module. That means that it is possible to determine whether a file has
been run directly by testing require.main === module.
Now I can connect to the mocked database from test.ts and only one connection will be triggered.
I'm trying to create a basic caching app just to test redis. Im using Redis Version: 4.0.6.
First I was getting error clientclosederror: the client is closed.
Then, after reading the docs, I added
let client;
(async ()=> {
client = redis.createClient()
await client.connect()
})();
But now, when trying on Postman, it just hangs, no response is returned
Full Code:
const express = require("express");
const redis = require("redis");
const axios = require('axios')
const app = express();
let client;
(async ()=> {
client = redis.createClient()
await client.connect()
})();
app.get('/result', async (req, res) => {
const searchTerm = req.query.name;
try {
await client.get(searchTerm, async (err, result) => {
console.log('cached called')
if (err) throw err;
if (result) {
res.status(200).send({
result: JSON.parse(result),
message: "data retrieved from the cache"
});
}
else {
const result = await axios.get(`https://api.agify.io/?name=${searchTerm}`);
await client.set(searchTerm, JSON.stringify(result.data));
return res.status(200).send({
result: result.data,
message: "cache miss"
});
}
})
} catch (error) {
console.log('get error', error)
return res.status(500).send({ message: error.message })
}
})
app.listen(process.env.PORT || 3000, () => {
console.log("Node server started");
});
client.get doesn't need a callback function. It's async. My guess is that it's never getting called and thus Express is not returning anything.
Try this instead:
const result = await client.get('foo')
if (result !== null) {
// it's a hit
} else {
// it's a miss
}
I'm making a little API using Node Js and Oracle, using node-oracledb for that. I have been guided by the following article: API with OracleDB and Node JS
The project files contain the following:
/services/web-server.js
const http = require('http');
const morgan = require('morgan');
const express = require('express');
const webServerConfig = require('../config/web-server');
let httpServer;
function initialize(){
return new Promise((resolve, reject) => {
const app = express();
httpServer = http.createServer(app);
app.use(morgan('combined'));
app.get('/', (req, res) => {
res.end('Hello World');
});
httpServer.listen(webServerConfig.port, err => {
if(err){
reject(err);
return;
}
console.log(`Web server listening on localhost:${webServerConfig.port}`);
resolve();
});
});
}
module.exports.initialize = initialize;
function close(){
return new Promise((resolve, reject) => {
httpServer.close(err => {
if(err){
reject(err);
return;
}
resolve();
});
});
}
module.exports.close = close;
/services/database.js
const oracledb = require('oracledb');
const dbConfig = require('../config/database');
async function initialize(){
const pool = await oracledb.createPool(dbConfig.gtsmpPool);
}
module.exports.initialize = initialize;
async function close(){
await oracledb.getPool().close();
}
module.exports.close = close;
And /index.js
const webServer = require('./services/web-server');
const database = require('./services/database');
const dbConfig = require('./config/database');
const defaultThreadPoolSize = 4;
// Increase thread pool size by poolMax
process.env.UV_THREADPOOL_SIZE = dbConfig.gtsmpPool.poolMax + defaultThreadPoolSize;
async function startup(){
console.log('Starting application');
try{
console.log('Initializing database module');
await database.initialize();
}catch(err){
console.error(err);
process.exit(1); // Non-zero failure code
}
try{
console.log('Initializing web server module');
await webServer.initialize();
}catch(err){
console.error(err);
process.exit(1); // Non-zero failure code
}
}
startup();
async function shutdown(e){
let err = e;
console.log('Shutting down');
try{
console.log('Closing web server module');
await webServer.close();
}catch(e){
console.log('Encountered error', e);
err = err || e;
}
console.log('Exiting process');
try{
console.log('Closing database module');
await database.close();
}catch(err){
console.log('Encountered error', err);
err = err || e;
}
if(err){
process.exit(1); // Non-zero failure code
}else{
process.exit(0);
}
}
process.on('SIGTERM', () => {
console.log('Received SIGTERM');
shutdown();
});
process.on('SIGINT', () => {
console.log('Received SIGINT');
shutdown();
});
process.on('uncaughtException', err => {
console.log('Uncaught exception');
console.error(err);
shutdown(err);
});
/config/database.js
module.exports = {
gtsmpPool: {
user: process.env.GTSMP_USER,
password: process.env.GTSMP_PASSWORD,
connectString: process.env.GTSMP_CONNECTIONSTRING,
poolMin: 10,
poolMax: 10,
poolIncrement: 0
}
};
The connection to the database is succesful. The problem is that when I want to terminate the application and close the connection pool, the await statement oracledb.getPool().close() never gets resolved and seems to get stuck.
If I try to forcefully finish I get the following messages
Encountered error Error [ERR_SERVER_NOT_RUNNING]: Server is not running.
at Server.close (net.js:1604:12)
at Object.onceWrapper (events.js:416:28)
at Server.emit (events.js:310:20)
at emitCloseNT (net.js:1657:8)
at processTicksAndRejections (internal/process/task_queues.js:83:21) {
code: 'ERR_SERVER_NOT_RUNNING'
And
Encountered error Error: NJS-002: invalid pool
I'm using Oracle 18c XE on docker container, Node v12.16.3 and instantclient_18_5
Any idea how to fix it?
Thanks.
There are some notes in the node-oracledb pool example...
// Get the pool from the pool cache and close it when no
// connections are in use, or force it closed after 10 seconds.
// If this hangs, you may need DISABLE_OOB=ON in a sqlnet.ora file.
// This setting should not be needed if both Oracle Client and Oracle
// Database are 19c (or later).
await oracledb.getPool().close(10);
I am using Hapi.js and have a route that I want to use to fetch data and then return a result.
I have tried to use async/await, but I must be doing something wrong because while the function I am calling eventually prints a result to the console, the route is returning without waiting for that function to return a value.
'use strict';
const Hapi = require('#hapi/hapi');
const HandyStorage = require('handy-storage');
var ethBalance ='';
// Connection to public blockchain via Infura.io
const Web3 = require("web3");
const web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io/v3/cf44bc52af3743bcad5f0b66813f8740"));
// Initialize Handy Storage
const storage = new HandyStorage({
beautify: true
});
//Get ETH address from Handy Storage
storage.connect('./preferences.json');
var walletAddress = storage.state.wallet;
// Get wallet balance
const getWalletBalance = async () => {
web3.eth.getBalance(`${walletAddress}`, async function(err, result) {
if (err) {
console.log('There was an error: ' + err);
return ({ error: 'The wallet balance call failed.' });
} else {
ethBalance = await web3.utils.fromWei(result, "ether");
console.log("This should be first: The wallet balance via API call is " + ethBalance + " ETH.");
return ethBalance; // I expect the walletbalance route to wait for this to be returned
}
});
};
// API Server
const init = async () => {
// Connection settings
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
// Get wallet balance
server.route({
method: 'GET',
path: '/walletbalance/',
handler: async (request, h) => {
let result = null;
try {
result = await getWalletBalance();
console.log('This should be second, after the getWalletBalance function has printed to the console.'); // this prints first, so await isn't working as expected
return ({ ethBalance: result });
} catch (err) {
console.log('Error in walletbalance route');
}
}
});
// 404 error handling
server.route({
method: '*',
path: '/{any*}',
handler: function (request, h) {
return ({
message: 'Error!'
});
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
Any idea where I have gone wrong here? This is the first time I have used async/await.
ETA: My console looks like this:
[nodemon] starting `node index.js`
Server running on http://localhost:3000
This should be second, after the getWalletBalance function has printed to the console.
This should be first: The wallet balance via API call is 4061.894069996147660079 ETH.
And this is the JSON I get back when I use the wallet balance route:
{}
Based on the answer I was given, I was able to get the results I wanted with this:
'use strict';
const Hapi = require('#hapi/hapi');
const HandyStorage = require('handy-storage');
var ethBalance ='';
// Connection to public blockchain via Infura.io
const Web3 = require("web3");
const web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io/v3/cf44bc52af3743bcad5f0b66813f8740"));
// Initialize Handy Storage
const storage = new HandyStorage({
beautify: true
});
//Get ETH address from Handy Storage
storage.connect('./preferences.json');
var walletAddress = storage.state.wallet;
// Get wallet balance
async function getWalletBalance(){
let ethBalance = await web3.eth.getBalance(`${walletAddress}`);
if (ethBalance.err) {
console.log('error in the called function');
} else {
return ethBalance;
}
}
// API Server
const init = async () => {
// Connection settings
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
// Get wallet balance
server.route({
method: 'GET',
path: '/walletbalance/',
handler: async (request, h) => {
try {
const result = await getWalletBalance();
const ethBalanceInWei = web3.utils.fromWei(result, "ether");
return ({ balance: ethBalanceInWei });
} catch (err) {
console.log('Error in walletbalance route');
}
}
});
// 404 error handling
server.route({
method: '*',
path: '/{any*}',
handler: function (request, h) {
return ({
message: 'Error!'
});
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
Thank you for the help! That got me going in the right direction.
Basically your getWalletBalance function is using multiple concepts. callback style functions and inside that you are using await. I have restructured your code a little bit. Hopefully that should fix the issue which you are facing.
'use strict';
const Hapi = require('#hapi/hapi');
const HandyStorage = require('handy-storage');
var ethBalance ='';
// Connection to public blockchain via Infura.io
const Web3 = require("web3");
const web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io/v3/cf44bc52af3743bcad5f0b66813f8740"));
// Initialize Handy Storage
const storage = new HandyStorage({
beautify: true
});
//Get ETH address from Handy Storage
storage.connect('./preferences.json');
var walletAddress = storage.state.wallet;
function getWalletBalance() {
return Promise((resolve, reject) => {
web3.eth.getBalance(`${walletAddress}`, (err, result) => {
if (err) {
console.log('There was an error: ' + err);
reject({ error: 'The wallet balance call failed.' });
} else {
resolve(result);
}
});
});
}
// API Server
const init = async () => {
// Connection settings
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
// Get wallet balance
server.route({
method: 'GET',
path: '/walletbalance/',
handler: async (request, h) => {
try {
const result = await getWalletBalance();
ethBalance = await web3.utils.fromWei(result, "ether");
return ethBalance;
} catch (err) {
console.log('Error in walletbalance route');
}
}
});
// 404 error handling
server.route({
method: '*',
path: '/{any*}',
handler: function (request, h) {
return ({
message: 'Error!'
});
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
I created a app.js file and there I am trying to connect with mongoDB atlas. The error '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()' is throwing when I run in terminal.
const connect = async function () {
const MongoClient = require('mongodb').MongoClient;
const uri = "mymongoDB atals url for nodejs";
MongoClient.connect(uri, { useNewUrlParser: true });
const collection = client.db("feedback").collection("itinerary");
// perform actions on the collection object
client.close();
};
connect().then(() => {
console.log('handle success here');
}).catch((exception) => {
console.log('handle error here: ', exception)
})
Try putting the async function operations in try catch block as below. I hope this should do the work.
const connect = async function () {
try {
const MongoClient = require('mongodb').MongoClient;
const uri = "mymongoDB atals url for nodejs";
MongoClient.connect(uri, { useNewUrlParser: true });
const collection = client.db("feedback").collection("itinerary");
// perform actions on the collection object
client.close();
} catch (e) {
console.log("Error", e)
}
};
connect().then(() => {
console.log('handle success here');
}).catch((exception) => {
console.log('handle error here: ', exception)
})
Try this:
const MongoClient = require('mongodb').MongoClient;
const connect = function () {
return new Promise((resolve, reject) => {
try {
const uri = "mymongoDB atals url for nodejs";
const client = new MongoClient(uri, { useNewUrlParser: true });
client.connect(err => {
if (err) {
reject(err)
}
const collection = client.db("feedback").collection("itinerary");
client.close();
resolve();
});
} catch (e) {
reject(e);
}
})
};
connect().then(() => {
console.log('handle success here');
}).catch((exception) => {
console.log('handle error here: ', exception)
})
Try this approach:
const MongoClient = require('mongodb').MongoClient;
// replace the uri string with your connection string.
const uri = "mymongoDB atals url for nodejs"
MongoClient.connect(uri, function(err, client) {
if(err) {
console.log('handle error here: ');
}
console.log('handle success here');
const collection = client.db("feedback").collection("itinerary");
// perform actions on the collection object
client.close();
});
Try by wrapping all the content of your function in a try/catch block:
const connect = async function () {
try {
const MongoClient = require('mongodb').MongoClient;
const uri = "mymongoDB atals url for nodejs";
MongoClient.connect(uri, { useNewUrlParser: true });
// most probably this is throwing the error. Notice the extra await
const collection = await client.db("feedback").collection("itinerary");
// perform actions on the collection object
client.close();
} catch (e) {
console.log(`Caught error`,e)
}
};
connect().then(() => {
console.log('handle success here');
}).catch((exception) => {
console.log('handle error here: ', exception)
})