Stack => Nodejs, Express.js, Typeorm
I'm trying to use typeorm with typescript. I have created a repository to save the survivor information. But I keep getting this error:
ConnectionNotFoundError: Connection "default" was not found.
at new ConnectionNotFoundError (/Users/Wblech/codeminerTeste/backend/src/error/ConnectionNotFoundError.ts:8:9)
at ConnectionManager.get (/Users/Wblech/codeminerTeste/backend/src/connection/ConnectionManager.ts:40:19)
at Object.getRepository (/Users/Wblech/codeminerTeste/backend/src/index.ts:284:35)
at new CreateSurvivorRepository (/Users/Wblech/codeminerTeste/backend/src/repositories/typeorm/CreateSurvivorRepository.ts:10:26)
at Object.<anonymous> (/Users/Wblech/codeminerTeste/backend/src/useCases/CreateSurvivor/index.ts:6:41)
at Module._compile (internal/modules/cjs/loader.js:774:30)
at Module._compile (/Users/Wblech/codeminerTeste/backend/node_modules/source-map-support/source-map-support.js:547:25)
at Module.m._compile (/private/var/folders/fr/6x3p83cj6r73h57k1_x6nctc0000gn/T/ts-node-dev-hook-7748782675459163.js:69:33)
at Module._extensions..js (internal/modules/cjs/loader.js:785:10)
at require.extensions..jsx.require.extensions..js (/private/var/folders/fr/6x3p83cj6r73h57k1_x6nctc0000gn/T/ts-node-dev-hook-7748782675459163.js:114:20)
[ERROR] 00:28:59 ConnectionNotFoundError: Connection "default" was not found.
My ormconfig.json is this one:
{
"name": "default",
"type": "postgres",
"host": "localhost",
"port": 5432,
"username": "postgres",
"password": "teste",
"database": "codeminer_backend",
"entities": [
"src/database/models/*.ts"
],
"migrations": [
"src/database/migrations/*.ts"
],
"cli": {
"migrationsDir": "./src/database/migrations"
}
}
Those are the code that the error appoint:
at new CreateSurvivorRepository (/Users/Wblech/codeminerTeste/backend/src/repositories/typeorm/CreateSurvivorRepository.ts:10:26)
import { getRepository, Repository } from 'typeorm'
import { SurvivorOrm } from '../../database/models/SurvivorsOrm'
import { ICreateSurvivorRequestDTO } from '../../useCases/CreateSurvivor/CreateSurvivorDTO'
import { ICreateSurvivorRepository } from '../ICreateSurvivorRepository'
export class CreateSurvivorRepository implements ICreateSurvivorRepository {
private ormRepository: Repository<SurvivorOrm>
constructor () {
this.ormRepository = getRepository(SurvivorOrm)
}
public async create ({ id, name, age, gender, lastLocation, infected }: ICreateSurvivorRequestDTO): Promise<SurvivorOrm> {
const survivor = await this.ormRepository.create({ id, name, age, gender, lastLocation, infected })
await this.ormRepository.save(survivor)
return survivor
}
}
at Object.<anonymous> (/Users/Wblech/codeminerTeste/backend/src/useCases/CreateSurvivor/index.ts:6:41)
import { CreateInventoryRepository } from '../../repositories/typeorm/CreateInventoryRepository'
import { CreateSurvivorRepository } from '../../repositories/typeorm/CreateSurvivorRepository'
import { CreateSurvivorController } from './CreateSurvivorController'
import { CreateSurvivorUseCase } from './CreateSurvivorUseCase'
const createSurvivorRepositoryTypeOrm = new CreateSurvivorRepository()
const createInventoryRepositoryTypeOrm = new CreateInventoryRepository()
const createSurvivorUseCase = new CreateSurvivorUseCase(
createSurvivorRepositoryTypeOrm,
createInventoryRepositoryTypeOrm
)
const createSurvivorController = new CreateSurvivorController(
createSurvivorUseCase
)
export { createSurvivorUseCase, createSurvivorController }
My connection is in a file in the path './src/database/index.ts' and is this one:
import { createConnection } from 'typeorm'
createConnection()
And I import the connection in this file called server.ts:
import express from 'express'
import { router } from './router'
import './database'
const port = 8081
const app = express()
app.use(express.json())
app.use(router)
app.listen(port, () => console.log(`App running at ${port}`))
I'm really stuck at this
Basically - TypeORM tries to get the "default" connection option, but If not found then throws an error:
ConnectionNotFoundError: Connection "default" was not found.
We can solve this issue by doing some kind of sanity check before establishing a connection - luckily we have .has() method on getConnectionManager().
import { Connection, getConnectionManager, getConnectionOptions,
createConnection, getConnection, QueryRunner } from 'typeorm';
async init() {
let connection: Connection;
let queryRunner: QueryRunner;
if (!getConnectionManager().has('default')) {
const connectionOptions = await getConnectionOptions();
connection = await createConnection(connectionOptions);
} else {
connection = getConnection();
}
queryRunner = connection.createQueryRunner();
}
Related
index.ts
import express, { Express } from 'express';
import dotenv from 'dotenv';
import { DataSource } from 'typeorm';
import cors from 'cors';
import bodyParser from 'body-parser';
import { Task } from './src/tasks/tasks.entity';
import { tasksRouter } from './src/tasks/tasks.router';
// Instantiate express app
const app: Express = express();
dotenv.config();
//Parsing incoming request
app.use(bodyParser.json());
//Use CORS install types as well
app.use(cors());
// Create Databse Connection
export const AppDataSource = new DataSource({
type: 'mysql',
host: 'localhost',
port: 3306,
username: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DB,
entities: [Task],
synchronize: true,
logging: true,
});
//Define Server Port
const port = process.env.PORT;
AppDataSource.initialize()
.then(() => {
// Start listening Request on defined port
app.listen(port);
console.log('Data Source has been initialized');
})
.catch((err) => console.log(err));
//create a Route
app.use('/', tasksRouter);
tasks.router.ts
import { Request, Response, Router } from 'express';
import { validationResult } from 'express-validator';
import { tasksController } from './tasks.controller';
import { createValidator } from './tasks.validator';
export const tasksRouter: Router = Router();
tasksRouter.get('/tasks', tasksController.getAll);
tasksRouter.post(
'/tasks',
createValidator,
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
//#ts-ignore
async (req: Request, res: Response) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res
.json({
errors: errors.array(),
})
.status(400);
}
},
);
tasks.controller.ts
import { AppDataSource } from '../../index';
import { Task } from './tasks.entity';
import { instanceToPlain } from 'class-transformer';
import { Request, Response } from 'express';
class TasksController {
constructor(private taskRepository = AppDataSource.getRepository(Task)) {}
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
//#ts-ignore
public async getAll(req: Request, res: Response): Promise<Response> {
let allTasks: Task[];
try {
allTasks = await this.taskRepository.find({
order: {
date: 'ASC',
},
});
allTasks = instanceToPlain(allTasks) as Task[];
res.json(allTasks).status(200);
} catch (_errors) {
return res.json({ error: 'Internal Server Error' }).status(500);
}
}
}
export const tasksController = new TasksController();
Hi everyone, I wish you all a very Happy New Year.
I have a question, While accessing the Task Entity, I have been getting error in the tasks.controller.ts file and
TypeError: Cannot read properties of undefined (reading
'getRepository')
What can be the actual Issue? What difference soes it make if I Instantiate the class in tasks.controller.ts file instead of the tasks.router.ts file? coz it is working if I Instantiate the TasksController class inside the route
I have followed this tutorial
https://joyofcode.xyz/using-websockets-with-sveltekit
and implemented a basic websocket server that sends a message to the client when he connects.
I want to also send a message when someone submits a form.
// socketIo.ts.js
import { Server } from 'socket.io';
let io
export function injectSocketIO(server) {
io = new Server(server);
io.on('connection', (socket) => {
socket.emit('eventFromServer', 'Hello, World 👋')
});
console.log('SocketIO injected');
}
export function send(sms){
io.emit('eventFromServer', sms);
}
export function getIO(){return io}
//vite.config.ts
import { sveltekit } from '#sveltejs/kit/vite';
import type { UserConfig } from 'vite';
import { injectSocketIO } from './socketIo.js';
import { Server } from 'socket.io'
const webSocketServer = {
name: 'webSocketServer',
configureServer(server) {
injectSocketIO(server.httpServer);
},
}
const config: UserConfig = {
plugins: [sveltekit(), webSocketServer]
};
export default config;
//my form action
import { send } from './socketIo.ts'
export const actions = {
default: async({ request }) =>{
console.log(send('da'))
I'm getting this error
Cannot read properties of undefined (reading 'emit')
TypeError: Cannot read properties of undefined (reading 'emit')
at Module.send (/home/runner/sveltekit-cpp/socketIo.ts:17:5)
at default (/home/runner/sveltekit-cpp/src/routes/+page.server.ts:10:16)
at call_action (file:///home/runner/sveltekit-cpp/node_modules/#sveltejs/kit/src/runtime/server/page/actions.js:204:9)
at handle_action_request (file:///home/runner/sveltekit-cpp/node_modules/#sveltejs/kit/src/runtime/server/page/actions.js:134:22)
at render_page (file:///home/runner/sveltekit-cpp/node_modules/#sveltejs/kit/src/runtime/server/page/index.js:65:26)
at async resolve (file:///home/runner/sveltekit-cpp/node_modules/#sveltejs/kit/src/runtime/server/index.js:247:17)
at async respond (file:///home/runner/sveltekit-cpp/node_modules/#sveltejs/kit/src/runtime/server/index.js:298:20)
at async file:///home/runner/sveltekit-cpp/node_modules/#sveltejs/kit/src/exports/vite/dev/index.js:418:22
I have tried exporting a send function from my socketIo file but it didn't work
So I'm in the process of learning NestJs ways. I have a small NestJs backend with only a few routes. Some of them call postgreSQL. I don't want to use any ORM and directly use pg package.
So my next step is learning how to use ConfigService. I have successfully used it to configure all env vars in the backend, but I'm struggling to use it in a small file I use to configure postgreSQL. This is the configuration file (pgconnect.ts):
import { Pool } from 'pg';
import configJson from './config/database.json';
import dotenv from 'dotenv';
dotenv.config();
const config = configJson[process.env.NODE_ENV];
const poolConfig = {
user: config.username,
host: config.host,
database: config.database,
password: config.password,
port: config.port,
max: config.maxClients
};
export const pool = new Pool(poolConfig)
database.json is a json file where I have all connect values divided by environment. Then in service classes I just:
import { Injectable } from '#nestjs/common';
import { Response } from 'express';
import { pool } from 'src/database/pgconnect';
#Injectable()
export class MyService {
getDocumentByName(res: Response, name: string) {
pool.query(
<query, error treatment, etc>
});
}
<...> more queries for insert, update, other selects, etc
}
So how could I use ConfigService inside my configuration file ? I already tried to instance class like this:
let configService = new ConfigService();
and what I would like to do is:
const config = configJson[configService.get<string>('NODE_ENV')];
but it didn't work. You have to pass .env file path to new ConfigService(). And I need to use NODE_ENV var to get it, because it depends on environment. To get NODE_ENV without using ConfigService I would have to use dotenv, but if I'm going to use dotenv I don't need ConfigService in the first place.
So then I tried to create a class:
import { Injectable, HttpException, HttpStatus } from '#nestjs/common';
import { ConfigService } from '#nestjs/config'
const { Pool } = require('pg');
import configJson from './config/database.json';
#Injectable()
export class PgPool {
constructor(private configService: ConfigService) { };
config = configJson[this.configService.get<string>('NODE_ENV')];
poolConfig = {
user: this.config.username,
host: this.config.host,
database: this.config.database,
password: this.config.password,
port: this.config.port,
max: this.config.maxClients
};
static pool = new Pool(this.poolConfig);
}
export const PgPool.pool;
But this doesn't work in several ways. If I use non-static members, I can´t export pool member which is the only thing I need. If I use static members one can't access the other or at least I'm not understanding how one access the other.
So, the questions are: How do I use ConfigService outside of a class or how can I change pgconnect.ts file to do it's job ? If it's through a class the best would be to export only pool method.
Also if you think there's a better way to configure postgreSQL I would be glad to hear.
What I would do, if you're going to be using the pg package directly, is create a PgModule that exposes the Pool you create as a provider that can be injected. Then you can also create a provider for the options specifically for ease of swapping in test. Something like this:
#Module({
imports: [ConfigModule],
providers: [
{
provide: 'PG_OPTIONS',
inject: [ConfigService],
useFactory: (config) => ({
host: config.get('DB_HOST'),
port: config.get('DB_PORT'),
...etc
}),
},
{
provide: 'PG_POOL',
inject: ['PG_OPTIONS'],
useFactory: (options) => new Pool(options),
}
],
exports: ['PG_POOL'],
})
export class PgModule {}
Now, when you need to use the Pool in another service you add PgModule to that service's module's imports and you add #Inject('PG_POOL') private readonly pg: Pool to the service's constructor.
If you want to see an overly engineered solution, you can take a look at my old implementation here
I normally have my own pg module handling the pool with either an additional config file (json) or via processing a .env file:
node-pg-sql.js:
/* INFO: Require json config file */
const fileNameConfigPGSQL = require('./config/pgconfig.json');
/* INFO: Require file operations package */
const { Pool } = require('pg');
const pool = new Pool(fileNameConfigPGSQL);
module.exports = {
query: (text, params, callback) => {
const start = Date.now()
return pool.query(text, params, (err, res) => {
const duration = Date.now() - start
// console.log('executed query', { text, duration, rows: res.rowCount })
callback(err, res)
})
},
getClient: (callback) => {
pool.connect((err, client, done) => {
const query = client.query.bind(client)
// monkey patch for the query method to track last queries
client.query = () => {
client.lastQuery = arguments
client.query.apply(client, arguments)
}
// Timeout of 5 secs,then last query is logged
const timeout = setTimeout(() => {
// console.error('A client has been checked out for more than 5 seconds!')
// console.error(`The last executed query on this client was: ${client.lastQuery}`)
}, 5000)
const release = (err) => {
// calling 'done'-method to return client to pool
done(err)
// cleat timeout
clearTimeout(timeout)
// reset query-methode before the Monkey Patch
client.query = query
}
callback(err, client, done)
})
}
}
pgconfig.json:
{
"user":"postgres",
"host":"localhost",
"database":"mydb",
"password":"mypwd",
"port":"5432",
"ssl":true
}
If you prefer processing a .env file:
NODE_ENV=develepment
NODE_PORT=45500
HOST_POSTGRESQL='localhost'
PORT_POSTGRESQL='5432'
DB_POSTGRESQL='mydb'
USER_POSTGRESQL='postgres'
PWD_POSTGRESQL='mypwd'
and process the file and export vars:
var path = require('path');
const dotenvAbsolutePath = path.join(__dirname, '.env');
/* INFO: Require dotenv package for retieving and setting env-vars at runtime via absolute path due to pkg */
const dotenv = require('dotenv').config({
path: dotenvAbsolutePath
});
if (dotenv.error) {
console.log(`ERROR WHILE READING ENV-VARS:${dotenv.error}`);
throw dotenv.error;
}
module.exports = {
nodeEnv: process.env.NODE_ENV,
nodePort: process.env.NODE_PORT,
hostPostgresql: process.env.HOST_POSTGRESQL,
portPostgresql: process.env.PORT_POSTGRESQL,
dbPostgresql: process.env.DB_POSTGRESQL,
userPostgresql: process.env.USER_POSTGRESQL,
pwdPostgresql: process.env.PWD_POSTGRESQL,
};
I cannot work out why I would get a query undefined when I know my definitions are correct. graphiQL is picking up my schemes without problems:
Auto complete works fine:
After hitting ctrl+enter all the fields are entered, see above.
Then I execute the query and I'll get:
{
"errors": [
{
"message": "Cannot read property 'query' of undefined",
"locations": [
{
"line": 1,
"column": 3
}
],
"path": [
"allAwards"
]
}
],
"data": {
"allAwards": null
}
}
npm run graphql
"graphql": "nodemon -r dotenv/config --experimental-modules --inspect=[9222] graphql_server.js",
graphql_server.js
import express from 'express'
import pg from 'pg'
import graphqlHTTP from 'express-graphql'
import PAS from 'postgraphile-apollo-server'
import AP from 'apollo-server-express'
const { makeSchemaAndPlugin } = PAS
const { ApolloServer } = AP
const env = process.env.NODE_ENV || 'development'
const dbHost = process.env.DB_HOST
const dbPort = process.env.DB_PORT
const dbName = process.env.DB_NAME
const dbUser = process.env.DB_USER
const dbPwd = process.env.DB_PWD
const dbUrl = dbPwd
? `postgres://${dbUser}:${dbPwd}#${dbHost}:${dbPort}/${dbName}`
: `postgres://${dbHost}:${dbPort}/${dbName}`
const pgPool = new pg.Pool({
connectionString: dbUrl,
})
async function main() {
const { schema, plugin } = await makeSchemaAndPlugin(
pgPool,
'public', // PostgreSQL schema to use
{
// PostGraphile options, see:
// https://www.graphile.org/postgraphile/usage-library/
}
)
const server = new ApolloServer({
schema,
plugins: [plugin],
})
const app = express()
app.use(
'/graphql',
graphqlHTTP({
schema: schema,
graphiql: true,
})
)
server.applyMiddleware({ app })
app.listen({ port: 4000 }, () => console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`))
}
main().catch(e => {
console.error(e)
process.exit(1)
})
There are 2 rows currently in psql db for awards as well
You should not utilize middleware from both express-graphql and apollo-server in your express application. Because postgraphile-apollo-server works explicitly with ApolloServer, drop express-graphql altogether. Having both middleware is likely to cause unexpected issues since they listen on the same paths.
Apollo has abandoned GraphiQL in favor of GraphQL Playground. If you want to use GraphiQL with Apollo, you can use a package like express-graphiql-middleware.
I kept getting
res.jwt is not a function
I have installed jwt-express and import it like so
import jwt from 'jwt-express'
This is my auth.js
import Account from '../services/account.js'
import env from 'dotenv'
import _ from 'lodash'
const dotenv = env.config();
module.exports = {
/**
* Process the user login, generating and returning a token if successful.
*
* #return {res}
*/
async login(req, res, next) {
try {
let origin = req.headers.origin;
let accounts = await Account.getAccounts();
let account = _.find(accounts, {
'email_address' : req.body.username,
'password' : req.body.password
});
if (!account) {
res.send('Username/Password Wrong');
}
// res.send(account);
let authentication = res.jwt({
'email': account.email_address,
'id': account.account_id
});
res.send(authentication);
} catch (error) {
next(error)
}
}
};
index.js
import express from 'express'
import favicon from 'serve-favicon'
import path from 'path'
import bodyParser from 'body-parser'
import bluebird from 'bluebird'
import jwt from 'jwt-express'
import env from 'dotenv'
//Controllers
import fortinetController from './controllers/fortinet'
import authController from './controllers/auth.js'
//Logger
import logger from './config/logger.js'
//Constant
const router = express.Router();
const app = express();
const PORT = 3000;
const dotenv = env.config();
Promise = bluebird;
app.use(bodyParser.urlencoded({extended: true }));
app.use(bodyParser.json());
app.use(router)
app.use(express.static('public'))
app.use(favicon(path.join(__dirname,'public','favicon.ico')))
app.use(jwt.init('CARWASH', {cookies: false }));
router.get('/', (req,res) => {
res.send('Welcome to the backend provisioning daemon to program FortiManager')
});
router.post('/login', authController.login);
//Fortinet
router.post('/fortinet/login', fortinetController.login);
router.post('/fortinet/getSessionTimeOut', fortinetController.getSessionTimeOut);
router.post('/fortinet/logout', fortinetController.logout);
//Error handling function
app.use((err,req,res,next) => {
console.error(err.stack)
res.status(500).send(`Red alert! Red alert!: ${err.stack}`)
logger.error(`${req.method} ${req.url} - ${err.log || err.message}`);
});
app.listen(PORT, () => {
console.log(`Your server is running on ${PORT}`)
}
);
How can I debug this?
Update
I've tried to add this
console.log(jwt);
I got
[nodemon] 1.17.3
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `babel-node ./index.js`
{ active: [Function: active],
clear: [Function: clear],
create: [Function: create],
init: [Function: init],
options:
{ cookie: 'jwt-express',
cookieOptions: { httpOnly: true },
cookies: false,
refresh: true,
reqProperty: 'jwt',
revoke: [Function: revoke],
signOptions: {},
stales: 900000,
verify: [Function: verify],
verifyOptions: {} },
require: [Function: require],
valid: [Function: valid] }
Your server is running on 3000
You are not configuring express-jwt correctly.
You are using express-jwt completely wrong.
Let's walk through each point.
I'm not sure why you think you need to call jwt.init(...) when the documentation here states to simply do: jwt(...). So you'll need to make the following changes:
Change
app.use(jwt.init('CARWASH', {cookies: false }));
To
app.use(jwt({secret: 'CARWASH'}));
There does not exist a cookies options, not sure where you got that from.
Now express-jwt will only handle verification of the JWT. It does not generate JWT for as you are trying to do in your auth.js.
In order to generate JWT, you will need another module: jsonwebtoken. You will then use the module in your auth.js like so:
import jwt from "jsonwebtoken";
// ...
module.export = {
async login(req, res, next) {
try {
// ... auth logic omitted
// Here we generate the JWT
// Make sure the JWT secret is the SAME secret you used for express-jwt
let authentication = jwt.sign({
'email': account.email_address,
'id': account.account_id
}, 'CARWASH');
res.send(authentication);
}
catch (error) {
next(error);
}
}
}