I have the following module which connects to a Redis database, and I want to get the client instance so I can call it from other modules without creating a new instance each time, I did the following:
let client;
const setClient = ({ redis, config }) => {
client = redis.createClient({
host: config.redis.host,
port: config.redis.port
});
};
const getClient = () => {
return client;
};
const connect = ({ redis, config, logger }) => {
setClient({ redis, config });
client.on('connect', () => {
logger.info(`Redis connected on port: ${client?.options?.port}`);
});
client.on('error', err => {
logger.error(`500 - Could not connect to Redis: ${err}`);
});
};
module.exports = { connect, client: getClient() };
when i call the client from other modules using const { client } = require('./cache'); it gives me undefined
erase letClient() from top(the let) and on the bottom add const client = getClient() and on module exports just go with client instead of client: getClient()
I come up with the following solution:
const cacheClient = () => {
return {
client: undefined,
setClient({ redis, config }) {
client = redis.createClient({
host: config.redis.host,
port: config.redis.port
});
},
getClient() {
return client;
},
connect({ redis, config, logger }) {
this.setClient({ redis, config });
client.on('connect', () => {
logger.info(`Redis connected on port: ${client?.options?.port}`);
});
client.on('error', err => {
logger.error(`500 - Could not connect to Redis: ${err}`);
});
}
};
};
module.exports = cacheClient;
If there's a better approach please let me know.
Related
I have been learninng NodeJS and mongoDB by youtube, but unfortunately i faced with this problem, and here is my code file! thank you in advance!
db.js
const { MongoClient } = require("mongodb");
let dbConnection;
module.exports = {
connectToDb: (cb) => {
MongoClient.connect("mongodb://localhost:27017/bookstore")
.then((res) => {
dbConnection = res.db();
return cb();
})
.catch((error) => {
console.log(error);
return cb(error);
});
},
getDb: () => dbConnection,
};
index.js
const express = require("express");
const { connectToDb, getDb } = require("./db");
// init app and middleware
const app = express();
//db connection
let db;
connectToDb((xato) => {
if (!xato) {
app.listen(3000, () => {
console.log("The 3000 port is installed");
});
db = getDb();
return db;
}
});
//routes
app.get("/bookstore", (req, res) => {
let mybook = [];
// the collection name from mongoDB
db.collection("bookstore")
.find()
.sort({ author: 1 })
.forEach((book) => mybook.push(book))
.then(() => {
return res.sendStatus(200).json(mybook);
})
.catch(() => {
return res.sendStatus(500).send("there were an error");
});
// res.json({ MyWords: "I am coming from json res" });
});
it must return data from local mongodb database. But it is facing with the problem. Please give me a solution!
both .sendStatus and .json will try to response to client. So the second call will result in this error.
Just use res.json(mybook) and res.send("there were an error") is enough.
In case you want to maintain status code and also send data. Use res.status(500).send("there were an error").
I am testing a nodejs express API with a PG db wrapped with Prisma ORM
I configured a testing singleton instance as described by Prisma docs
Since the API is implemented in CommonJS and not TS, I had to make some changes as described in this beautiful page.
Here is a synthesis of what I did, will try to make it short, so it's easier to read
orgs.js (A GET route served by the mock server later on ...)
const Router = require('express-promise-router')
const router = new Router()
const PrismaPool = require('../db/PrismaPool');
module.exports = router
router.get('/assessments', async (req, res) => {
try{
const prisma = PrismaPool.getInstance();
const data = await prisma.org.findUnique({
select:{
assessments:true,
},
where: {
id: res.locals.orgId,
},
})
res.send(data)
}
catch(err){
handleError(err, "[GET]/orgs/assessments", 400, req, res)
}
})
PrismaPool.js (A wrapper to access the unique prisma client instance)
const prisma = require('./PrismaClientInstance').default
class PrismaPool {
constructor() {
throw new Error('Use PrismaPool.getInstance()');
}
static getInstance() {
return prisma
}
}
module.exports = PrismaPool;
PrismaClientInstance.js The unique instance of PrismaClient class. This is the tricky part stitching between the CommonJS world and the TS world.
'use strict';
exports.__esModule = true;
const { PrismaClient } = require('#prisma/client')
const prisma = new PrismaClient()
exports['default'] = prisma;
All this configuration works GREAT at runtime, now, when wrapping it with JEST in unit tests, things go south quickly ...
mock_server.js (a simplified server to expose the orgs API above)
const http = require('http');
const express = require('express');
var orgsRouter = require('../orgs');
const app = express();
app.use('/orgs', orgsRouter);
const port = 3011
app.set('port', port);
const server = http.createServer(app);
function onError(error) {
// herror handling
}
function onListening() {
// some debug messages
}
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
module.exports = server
PrismaSingletonForTesting.ts (A jest deep mock of the PrismaClient instance)
import { PrismaClient } from '#prisma/client'
import { mockDeep, mockReset, DeepMockProxy } from 'jest-mock-extended'
import prisma from './PrismaClientInstance'
jest.mock('./PrismaClientInstance', () => ({
__esModule: true,
default: mockDeep<PrismaClient>()
}))
beforeEach(() => {
mockReset(prismaMock)
})
export const prismaMock = prisma as unknown as DeepMockProxy<PrismaClient>
orgs.test.js (The tests of the orgs API)
const Request = require("request")
const { prismaMock } = require('../../db/PrismaSingletonForTesting')
const TEST_ORGID = 1
describe('egrest server', () => {
let server
beforeAll(() => {
server = require('./test_server')
})
afterAll(() => {
server.close()
})
describe('assessments', () => {
let data = {}
beforeAll(() => {
const testorg = {
id: TEST_ORGID,
name: 'jestest',
admin:33,
avail_tests: 1234
}
prismaMock.org.findUnique.mockResolvedValue(testorg)
})
it(`read remaining assessments for org ${TEST_ORGID}`, (done) => {
Request.get("http://localhost:3011/orgs/assessments", (error, response, body) => {
data.status = response.statusCode
data.body = body
data.error = error
console.dir(body)
done()
})
})
})
})
I also configured .jest.config with the required line setupFilesAfterEnv: ['./db/PrismaSingletonForTesting.ts']
When I run this test, I get data=undefined in orgs.js, even-though I mocked prisma.org.findUnique by doing prismaMock.org.findUnique.mockResolvedValue(testorg) as described by prisma docs.
Any help would be appreciated.
I have redis up and running on port 6379, connecting via telnet works fine.
I'm trying to connect to it on node.js, but i'm getting no response from the event listeners.
If i make a call any function like client.set() I get: "ClientClosedError: The client is closed".
This is the code im running:
const redis = require('redis');
const client = redis.createClient(6379);
client.on('connect', () => {
console.log('connected');
});
client.on('end', () => {
console.log('disconnected');
});
client.on('reconnecting', () => {
console.log('reconnecting');
});
client.on('error', (err) => {
console.log('error', { err });
});
setTimeout(() => {console.log("goodbye") }, 20*1000 );
Nothing happens for 20 seconds, and then it closes
Starting from v4 of node-redis library, you need to call client.connect() after initializing a client. See this migration guide.
const redis = require('redis');
const client = redis.createClient({ socket: { port: 6379 } });
client.connect();
client.on('connect', () => {
console.log('connected');
});
You might also want to consider running the client connect method with await in an asynchronous function. So you don't have to worry about event listeners.
const redis = require('redis');
(async () => {
try {
const client = redis.createClient({ socket: { port: 6379 } });
await client.connect();
console.log('connected');
} catch (err) {
console.error(err)
}
})()
I'm using hapi-nuxt in a javascript project similar to a Nuxt tutorial I am watching. I generated the skeleton app using:
npx create-nuxt-app <project-name>
That gives me the following code in server/index.js:
const Hapi = require('hapi')
const consola = require('consola')
const HapiNuxt = require('hapi-nuxt')
const server = new Hapi.Server({
host: process.env.HOST || 'localhost',
port: process.env.PORT || 3000
})
server
.register({
plugin: HapiNuxt
})
.then(() => server.start())
.then(() =>
consola.ready({
message: `Server running at: ${server.info.uri}`,
badge: true
})
)
.catch(err => {
consola.error(err)
throw err
})
Now I want to add the routes listed in server/routes/index.js. I believe the code is similar to:
const routes = require('./routes');
...
routes.forEach(route => {
app.route(route);
}
Assuming that code is correct, where do I put it?
Here is an example
// server/index.js
const consola = require('consola')
const Hapi = require('#hapi/hapi')
const HapiNuxt = require('#nuxtjs/hapi')
const Routes = require('./api')
async function start() {
const server = new Hapi.Server({
host: process.env.HOST || '127.0.0.1',
port: process.env.PORT || 3000
})
await server.register({
plugin: HapiNuxt,
options: {}
});
await server.route(Routes);
await server.start()
consola.ready({
message: `Server running at: ${server.info.uri}`,
badge: true
})
}
process.on('unhandledRejection', (error) => consola.error(error))
start()
// server/api/index.js
const route1 = {
path: '/api',
method: 'GET',
handler (request, h) {
return {
works: true
}
}
}
module.exports = [
route1
]
I am trying to create some unit tests with Mocha and Chai but I am unable to connect to the mysql server. Here I have my unit test:
process.env.NODE_ENV = 'test';
let chai = require('chai');
let chaiHttp = require('chai-http');
let server = require('../app');
let should = chai.should();
chai.use(chaiHttp);
describe('API endpoint /authenticate', function () {
before((done) => {
/* Todo: Clean up Database*/
done()
});
it('should authenticate a user given CORRECT username/password', (done) => {
let user = {
username: 'ax850',
password: 'test'
};
chai.request(server)
.post('/api/authenticate')
.send(user)
.end((err, res) => {
res.should.have.status(200);
done();
});
done();
});
});
As you can see, I am doing a POST request. Then in the script where I handle this POST request, I am connecting to a mySQL server like so:
const db = require('./../../db_conn');
And in the db_conn I have:
const mysql = require('mysql');
const config = require('config.json')('./config.json');
let db;
const db_config = config.a_c.dbConfig;
function connectDatabase() {
if (!db) {
db = mysql.createConnection({
host: db_config.host,
user: db_config.user,
port: db_config.port,
database: process.env.NODE_ENV === 'test' ? db_config.db_test : db_config.db_dev,
//database: db_config.db_dev,
password: db_config.password
});
db.connect(function(err){
if(!err) {
console.log('Database is connected!');
} else {
console.log('Error connecting database!');
}
});
}
return db;
}
module.exports = connectDatabase();
However, when I run my test command: mocha --timeout 10000, it doesn't connect to the database. The mysql.createConnection runs unsuccessfully but doesn't give an error either. Any ideas? This works when I run the server without testing.
You are calling done before the request finishes.
chai.request(server)
.post('/api/authenticate')
.send(user)
.end((err, res) => {
res.should.have.status(200);
done();
});
// this is executed before chai.request is fulfilled
done();