I'm learning NodeJS and the task is to build a simple messaging service. The teacher is using SQLite3, but I decided to use Postgres since it's the DB we use in our company projects.
Error: "ConnectionNotFoundError: Connection "default" was not found"
// server.ts
import 'reflect-metadata';
import express from 'express';
import { createConnection } from 'typeorm';
import router from './router';
(async () => {
const PORT = 3333;
console.log('before');
await createConnection();
console.log('after');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(router);
app.listen(PORT, () => {
console.log(`App is running on port ${PORT}`);
});
})();
I have the following MessagesService
// this works just fine
class MessagesService {
async create({ user_id, text, admin_id }: MessagesCreateInterface): Promise<Message> {
const repository = getCustomRepository(MessagesRepository);
const message = repository.create({
admin_id,
text,
user_id,
});
await repository.save(message);
return message;
}
async listByUser(user_id: string): Promise<Array<Message>> {
const repository = getCustomRepository(MessagesRepository);
const messages = await repository.find({ user_id });
return messages;
}
}
Since getCustomRepository
is called in both functions, and tried converting it to a class attribute:
class MessagesService {
repository: MessagesRepository;
constructor() {
console.log('constructor');
this.repository = getCustomRepository(MessagesRepository);
}
...
}
But then I get ConnectionNotFoundError: Connection "default" was not found.
.
Using a setTimeout
inside constructor
: The connection is accessed.
Consoles.log: I get "before" and "constructor" print, but not "after".
Can someone help me understand what's going on? As I'm using async/await, MessageService
shouldn't be called until the connection was established. Am I'm breaking some pattern here?
The problem is that router.js
is being imported before createConnection
is called on server.ts
.
Since the controllers are instantiated inside router.js
, alongside the services and repositories, they were indeed trying to access a database connection before it was created.
The solution I found is to lazily import router.js
after the connection has been established, but I'm not sure if that's an anti-pattern.
// server.ts
import 'reflect-metadata';
import express from 'express';
import { createConnection } from 'typeorm';
(async () => {
await createConnection();
// Importing routes after connection has been established
const router = (await import('./router').default);
const PORT = 3333;
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(router);
app.listen(PORT, () => {
console.log(`App is running on port ${PORT}`);
});
})();
The suggested way in the lectures was to create an instance of the controller inside every route, but it doesn't seem right to me.
router.js
// suggested way
router.post('/messages', (request, response) => {
const messagesController = new MessagesController();
return messagesController.create(request, response);
});
router.get('/messages/:id', (request, response) => {
const messagesController = new MessagesController();
return messagesController.showByUser(request, response);
});
Since I'm still learning NodeJS, feel free to correct me and point me to the right way.