Can we use all node npm packages in Nestjs - node.js

In current, I am learning Nestjs, I found that Nestjs have a list of its own npm package like #nestjs/cqrs, #nestjs/jwt etc. Full list of all packages is https://www.npmjs.com/org/nestjs.
Now I have a doubt that can we use all npm packages in nestjs that we use in any Node.js application like morgan, windston etc.
Or we can only use the packages that mention in nestjs documentation list.

First, node.js packages can be used in Nestjs with its custom provider. So see the current docs.
Second, Brunner on the Nestjs core team helped me with this on the Nestjs_framework Reddit. He made a nice brief example for us on Github. I asked him to change the name from reddit to node so that will break this link, but you can find it on his Github site. He deserves the credit.
We aren't supposed to link to a solution on SO. So let's get started.
Brunner changed my architecture and I like his approach. I wanted to use the Cloudinary Node SDK which doesn't have a Nestjs module. This should work for importing any Node package, at least that is my understanding.
Note: When you write this.cloudinary. you expect to see a list of methods after that '.' . You won't, so just use whatever code the SDK or package docs tells you to use. A little weirdness.
The Cloudinary components live in a folder inside my members directory, which has a bunch of modules imported into it.
cloudinary.module.ts
import { Module } from '#nestjs/common';
import { cloudinaryProvider } from './cloudinary.provider';
import { CloudinaryService } from './cloudinary.service';
#Module({
providers: [cloudinaryProvider, CloudinaryService],
exports: [cloudinaryProvider],
})
export class CloudinaryModule {}
cloudinary.provider.ts
import { Provider } from '#nestjs/common';
import * as CloudinaryLib from 'cloudinary';
export const Cloudinary = 'lib:cloudinary';
export const cloudinaryProvider: Provider = {
provide: Cloudinary,
useValue: CloudinaryLib,
};
cloudinary.service.ts
import { Injectable, Inject } from '#nestjs/common';
import { Cloudinary } from './cloudinary.provider';
#Injectable()
export class CloudinaryService {
constructor(
#Inject(Cloudinary) private cloudinary
) {
// console.log('This is the cloudinary instance:');
// console.log(this.cloudinary);
}
}
And finally the parent module:
members.module.ts
import { CloudinaryModule } from './cloudinary/cloudinary.module'
#Module({
imports: [
CloudinaryModule,
...

Nest will expose the http adapter so that you can hook into it, here is an example using the morgan & body-parser npm package:
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
import { ConfigService } from './config/config.service';
import { ConfigModule } from './config/config.module';
import bodyParser from 'body-parser';
import morgan from 'morgan';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const configService = app.select(ConfigModule).get(ConfigService);
app.use(bodyParser.json());
app.use(morgan('dev'));
app.enableCors();
await app.listen(configService.PORT, () => console.log(`Server listening on port ${configService.PORT}`));
}
bootstrap();
In this instance above appis an express instance.

Nest is a framework that runs on top of an HTTP adapter (the main two that I know of being Fastify and Express with Express being the default adapter). If the package you are wanting to work with works with express (such as Morgan) then it's no problem. If the package you are wanting to use is platform agnostic (like Pino or Winston) then there are no problems. If the package you want to use is for a different HTTP adapter (like koa-router) then you have a problem (the counter example being something like #hapi/joi which is maintained by the hapi framework maintainers, but is actually adaptable to work with anything). There are some typescript specific packages class-validator and class-transformer come to mind, but overall if the package works on any node environment, it can work for Nest. If you have any questions about packages and implementation you could always check out the discord and ask your question there.

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.

How to reference the app instance in a module in Nest.js

I'm working on a project that's using multiple Nest repos, around 4.
Every repo needs to implementing logging to log things like
Server lifecycle events
Uncaught errors
HTTP requests/responses
Ideally, I'd like to package everything up into a module which I can publish to my company's NPM organization and just consume directly in each of my projects.
That way, it would take very minimal code to get logging set up in each project.
One of the things I'd like to log in my server lifecycle event is the server's url.
I know you can get this via app.getUrl() in the bootstrapping phase, but it would be great to have access to the app instance in a module's lifecycle hook like so.
#Module({})
export class LoggingModule implements NestModule {
onApplicationBootstrap() {
console.log(`Server started on ${app.getUrl()}`)
}
beforeApplicationShutdown() {
console.log('shutting down')
}
onApplicationShutdown() {
console.log('successfully shut down')
}
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggingMiddleware).forRoutes('*')
}
}
Is this possible?
There's no way (besides hacky ones, maybe) to access the app itself inside modules.
As you can see here, app.getUrl() uses the underlying HTTP server. Thus I guess you can retrieve the same data using the provider HttpAdapterHost.
Ï thought I'd chime in and offer one of the hacky solutions. Only use this, if there is absolutely no other way or your deadline is coming in an hour.
Create a class that can hold the application instance
export class AppHost {
app: INesApplication
}
And a module to host it
#Module({
providers: [AppHost]
exports: [AppHost]
})
export class AppHostModule {}
In your bootstrap() function, retrieve the AppHost instance and assign the app itself
// after NestFactory.create() ...
app.select(AppHostModule).get(AppHost).app = app;
Now, the actual application will be available wherever you inject AppHost.
Be aware, though, that the app will not be available inside AppHost before the whole application bootstraps (in onModuleInit, onApplicationBootstrap hooks or in provider factories), but it should be available in shutdown hooks.
Not sure is that hacky... I'm using this to prevent the server from starting in case of pending migrations.
// AppModule.ts
export class AppModule implements NestModule {
app: INestApplication;
async configure(consumer: MiddlewareConsumer) {
if (await this.hasPendingMigrations()) {
setTimeout(()=> {
this.logger.error("There are pending migrations!")
process.exitCode = 1;
this.app.close();
}, 1000);
}
//...
}
public setApp(app: INestApplication) {
this.app = app;
}
//...
}
//main.ts
const app = await NestFactory.create(AppModule, {
logger: config.cfgServer.logger,
});
app.get(AppModule).setApp(app);

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');

App Object in Electron Module and getAppPath throws Error

I have a strange problem with my application. I get an error, and I can't solve it. First at all, I installed a new project, so everything is clean. Someone sent me this repo to use for an Angular, Electron and Nodejs Application. Everything worked fine, but then I decided to install an embedded database like sqlite3. For this I found NeDB, and the module is perfect for my needs. First I had the problem, has nothing to do with my general problem, that I can't create a database file. So I read that I can only create files in my application path, because something about Electron and that's working in a browser.
I found the getAppPath() method that is implemented in my app object from the Electron module. Here starts the problem. For hours I tried to get the application path from this object. Finally, I wrote this code.
import { Injectable } from '#angular/core';
var nedb = require('nedb');
import { app } from 'electron';
import * as path from 'path';
#Injectable()
export class DatabaseService {
app: typeof app;
Database: any;
constructor() {
this.app = window.require("electron").app;
this.Database = new nedb({ filename: path.join(this.app.getAppPath(), '/diary.db'), autoload: true, timestampData: true });
var scott = {
name: 'Scott',
twitter: '#ScottWRobinson'
};
this.Database.insert(scott, function(err, doc) {
console.log('Inserted', doc.name, 'with ID', doc._id);
});
}
}
And I get this error.
I found this posting, but I don't really understand what the post is trying to tell me. I followed the links, but nothing seems to help. Anyone have an idea?

Testing React Router with Jest and Enzyme

My goal is to test my React Router Route exports in my app and test if it is loading the correct component, page, etc.
I have a routes.js file that looks like:
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import { App, Home, Create } from 'pages';
export default (
<Route path="/" component="isAuthenticated(App)">
<IndexRoute component={Home} />
<Route path="create" component={Create} />
{/* ... */}
</Route>
);
Note: isAuthenticated(App) is defined elsewhere, and omitted.
And from what I've read, and understood, I can test it as such:
import React from 'react';
import { shallow } from 'enzyme';
import { Route } from 'react-router';
import { App, Home } from 'pages';
import Routes from './routes';
describe('Routes', () => {
it('resolves the index route correctly', () => {
const wrapper = shallow(Routes);
const pathMap = wrapper.find(Route).reduce((pathMapp, route) => {
const routeProps = route.props();
pathMapp[routeProps.path] = routeProps.component;
return pathMapp;
}, {});
expect(pathMap['/']).toBe(Home);
});
});
However, running this test results in:
Invariant Violation: <Route> elements are for router configuration only and should not be rendered
I think I understand that the issue might be my use of Enzyme's shallow method. I took this solutions from this SO question. I believe I understand that it is attempting to parse through the wrapper in search of a Route call, putting each into a hashtable and using that to determine if the correct component is in the table where it should be, but this is not working.
I've looked through a lot of documentation, Q&A, and blog posts trying to find "the right way" to test my routes, but I don't feel I'm getting anywhere. Am I way off base in my approach?
React: 15.4.2
React Router: 3.0.2
Enzyme: 2.7.1
Node: 6.11.0
You can't directly render Routes, but a component with Router that uses routes inside. The answer you pointed to has the complete solution.
You will probably also need to change the browserHistory under test environment to use a different history that works on node. Old v3 docs:
https://github.com/ReactTraining/react-router/blob/v3/docs/guides/Histories.md
As a side note, what's the point of testing Route which I assume is already tested in the library itself? Perhaps your test should focus on your route components: do they render what they should based on route params? Those params you can easily mock in your tests because they're just props.
I'm telling you this because in my experience understanding what to test was as important as learning how to test. Hope it helps :)

Resources