TypeORM Connection "default" was not found when using a routes file and repository pattern - node.js

I have a TS project where I'm using TypeORM. I'm using Repository pattern so I have layers: Controller -> Service -> Repository.
The Controller constructor initialize the Service class which initialize Repository class, where the constructor is:
constructor(){
this.ormRepository = getRepository(TypeormEntity)
}
This works fine when I create the routes in the index.ts like this:
createConnection().then(() => {
const controller = new MyController()
app.get('/', controller.getSomething);
})
The connection is created and then I initialize the class using new MyController().
The problem is when I want to get the routes in another file. I want to get this structure folder:
src
|--> index.ts
|--> routes
|--> v1
|--> router.ts
|--> value
|--> value.route.ts
|--> v2
|--> ...
So, to achieve this, the index.ts import the routes. But the problem is, as the import is done, the MyController() constructor is executed and the execution fails.
So I want to have something like this in index.ts
import * as express from 'express'
import { createConnection } from "typeorm";
import Router from './routes/v1/router'
const app = express()
createConnection().then(() => {
app.use('/', Router)
app.listen(port)
})
Also, following the import call, the file router.ts in routes/v1 is:
import { json, Router } from 'express'
import valueRouter from './value/value.route'
const router = Router()
router.use(json())
router.use('/value', valueRouter)
export default router
This is to add a "prefix" to all routes depending the resource they call.
And value.route.ts is where the controller is initialized and fails.
import { Router } from "express";
import ValueController from '../../../controller/value.controller'
const router = Router()
const vc = new ValueController()
router.get('/',vc.getSomething)
export default router
I've tested deleting the constructor and the project intializes ok, so the problem is the repository initialization accross Controller & Service.
How can I achieve this?
Thanks in advance.

Finally I solved my own issue using dynamic imports.
Now my index.ts looks like this:
createConnection().then(() => {
import('./routes/v1/router').then((router: any) => {
app.use('/', router.default)
app.listen(port)
})
})
Which I think is much cleaner than having all routes added in this file. Calling routes in an external file I can manage a huge amount and maintain a clean structure.

Related

How to declare variable of type Express in TypeScript without importing express?

I have main file called main.ts where I imported express with
import express from 'express';
Then I have another class in separate file where I want to create method "init" which has one parameter named "app" of type Express. But somehow i can't say app:Express without importing express.
My goal is to import express only once and keep it in a main.ts file, and then in a main.ts file I will call "init" method ( from a separate file) where I will pass that imported express.
Main.ts file
import express from 'express';
import { FriendsRouter } from './routes/friends.router';
const app = express();
FriendsRouter.init(app);
const PORT:number = 3000;
app.listen(PORT,()=>{
console.log('Listening at '+PORT);
})
Spearete file (friends router in my case)
export class FriendsRouter {
private constructor(){
}
public static init(app:Express): void{
app.get('/friends',someMethod);
}
}
Problem is, in FriendsRouter file, I can't say app: Express.
How can I fix this ?
The usual thing is to import the type Express from the express package:
import { Express } from "express";
Note that that's just importing the type, not the function. The rest of your code is then fine as-is (including the type on app).
If you don't have that type, install the types for express like this:
npm install --save-dev #types/express
...but you've probably already done that.

typescript express get does not work in separate files

I'm currently converting my node code to node-ts to help our development flow for someone that is going to help out.
I tried using this information (typescript node.js express routes separated files best practices) initially but that didn't work, so as of right now I have this below
In my index.ts I have this on the bottom
import Auth from "./routes/Auth";
app.use('/auth', Auth.Routing());
export = app;
Then in my ./routes/Auth.ts I have this
const Routing = function() {
app.get('/session', User.session);
return app;
}
export = { Routing };
When I try to access /auth/session all it returns is index_1.default.get.
Using the link above, I attempted to use const router = express.Router(); and then export = router and what not but was unable to get it to work for that either with the same error.

Set "basedir" option for Pug in NestJS

I'm trying to use pug layouts in NestJS, however when extending a layout from an absolute path, pug requires the basedir option to be set.
In ExpressJS you would use app.locals.basedir = ..., what would be the equivalent in NestJS?
const server = await NestFactory.create<NestExpressApplication>(AppModule);
server.setViewEngine('pug');
server.setBaseViewsDir(join(__dirname, 'templates', 'views'));
await server.listen(config.server.port);
Using extends /layouts/index in a view would throw the following; the "basedir" option is required to use includes and extends with "absolute" paths.
I'm not looking to use relative paths, since this quickly becomes very messy. E.g. extends ../../../layouts/index
From what I can tell, you can achieve the same functionality as /layouts/index with just using layout/index so long as layout is a folder in your templates/views directory.
I've set up a git repo as a working example so you can test it out yourself and see if I need to go in more depth about anything.
EDIT 6/27/2019:
Thank you, I misunderstood your initial question.
With creating and express based application, you can send an express server to the NestFactory to use that server instance instead of having Nest create a plain instance for you. From here you can set up the express server as you normally would and get the desired functionality. I've modified the git repo to be able to test the scenario better and believe this is what you are looking for.
My main.ts
import { NestFactory } from '#nestjs/core';
import { NestExpressApplication, ExpressAdapter } from '#nestjs/platform-express';
import * as express from 'express';
import { AppModule } from './app.module';
import { join } from 'path';
async function bootstrap() {
// Creating and setting up the express instanced server
const server = express();
server.locals.basedir = join(__dirname, '..', 'views');
// Using the express server instance in the nest factory
const app = await NestFactory.create<NestExpressApplication>(AppModule, new ExpressAdapter(server));
app.useStaticAssets(join(__dirname, '..', 'public'));
app.setBaseViewsDir(join(__dirname, '..', 'views'));
app.setViewEngine('pug');
await app.listen(3000);
}
bootstrap();
Overall the folder set up is like so
src
|-app.controller.ts
|-app.module.ts
|-app.service.ts
|-main.ts
views
|-hello
|-home.pug
|-message
|-message.pug
|-templates
|-layout.pug
And the beginning of my home.pug and message.pug files is extends /templates/layout
After looking around through the documentation, NestJS uses an express under the hood, and gives you access to the underlying instance with getHttpAdapter().getInstance().
Keeping that in mind, we can set the basedir as follows;
const express = server.getHttpAdapter().getInstance();
express.locals.basedir = join(__dirname, 'templates');

How to import a default export of webpack entry file from outside?

I think I can best explain it with code. I have a file in webpack like the following:
import ReactDOMServer from 'react-dom/server';
import Server from './server';
import templateFn from './template';
export default (req, res) => {
const reactString = ReactDOMServer.renderToString(<Server />);
const template = templateFn(html);
res.send(template);
};
I also have an express application where I want to have access to the default exported function. If it makes any difference, this file is the webpack entry file. Here is what I tried in my express app:
const handleRequest = require(path.resolve(webpackConfig.output.path, webpackConfig.output.filename));
app.get('*', (req, res) => {
console.log(handleRequest);
});
I was trying to import the webpack generated file with the hope that I will be able to access the entry file's default export. Well, I was wrong as the output of the import was {}.
Is there a webpack plugin or some kind of a technique to do what I am trying to build? I don't want the express application to be part of the webpack build. That was the main reason I separated the code in this way.
I was able to access contents of webpack using library parameter (webpack.config.js):
output: {
path: ...,
filename: ...,
library: 'myapp',
libraryTarget: 'commonjs'
}
Then access it in the code:
const output = require(path.resolve(webpackConfig.output.path, webpackConfig.output.filename));
const defaultExportFunction = output.myapp.default;

extending express application interface

I am trying to extend the expressjs Application interface using declaration merging as explained in the express type definitions
declare module Express {
// These open interfaces may be extended in an application-specific manner via declaration merging.
// See for example method-override.d.ts (https://github.com/borisyankov/DefinitelyTyped/blob/master/method-override/method-override.d.ts)
export interface Request { }
export interface Response { }
export interface Application { }
}
So, my app.ts looks like this:
/// <reference path="typings/express/express.d.ts" />
declare module Express {
export interface Application {
testA: string;
}
export interface Request {
testR: string;
}
}
import express = require('express');
var app = express();
app.testA = "why not?";
app.use(function (req, res, next) {
req.testR = "xxx";
})
I get the errors:
"Property testA does not exist on type Express"
"Property testR does not exist on type Request"
Any clues?
Since you are using modules, declaration merging won't happen here. In app.ts there isn't an Express module to merge with so it's making a completely separate module definition. You need to move the code...
declare module Express {
export interface Application {
testA: string;
}
export interface Request {
testR: string;
}
}
...into a .d.ts file so that the interfaces are merged with the ones in express.d.ts.

Resources