How to implement database first approach in Nest JS - node.js

I have three schemas(User, Account, Contact) these three schemas used to created a model and generate the migration files also Next, this migration file migrate the PostgreSQL Database this part successfully completed using Nest JS.
Next, Manually I created one table and added few columns in the table. In this table(model) I need automatically integrate in our Nest JS CODE is it possible?
So, I google it how to achieve this scenario this given one solution schema first approach.
In Nest JS used one Library that is GraphQL this library used to achieve schema first approach. I
tried this approach but I could not get the database model in our code.
Anyone tell me how to achieve this scenario

/Combining NestJS and Prisma provides a new level of type-safety that is impossible to achieve with any other ORM from the Node.js & TypeScript ecosystem. This example demonstrates how to use Prisma Client./
import { Injectable, OnModuleInit, INestApplication } from '#nestjs/common'
import { PrismaClient } from '#prisma/client'
#Injectable()
export class PrismaService extends PrismaClient
implements OnModuleInit {
async onModuleInit() {
await this.$connect();
}
async enableShutdownHooks(app: INestApplication) {
this.$on('beforeExit', async () => {
await app.close();
});
}
}

Related

Can i use Prisma-Client as a nested dependency

I was making a restful APIs framework I decided to add Prisma for database support I want to provide Prisma-client to users in an appropriate way.
here is what I'm trying to do:
// #my/pkg
import {PrismaClient} from '#prisma/client'; // here the prisma client is nested dependency for client
// base class for all routes, the user will extend this class to create a route
abstract class BaseRouter {
public get (req: Request, res: Response): Promise <void> {}
public db = new PrimaClient ();
}
// client side
// note! prisma init and database will setup on client side
import BaseRouter from '#my/pkg'
class Client extends BaseRouter {
public get (req: Request, res: Response): Promise <void> {
const users = db.Users.findMany (); // I'm getting error here
}
}
so my question is can I use pirsma-client as a nested dependency and is there any way to achieve similar results?
Reason for that Design:
I'm providing database access from the base class because I also want to provide other databases like Redis, firebase, etc... according to the flavor of the database chosen by the user.
here how it looks like:-
which database do you want to choose for your app:
- Prisma (SQL/MongoDB)
- firebase (NON-SQL)
- Redis (caching)
According to APIS design, all databases will access through the base class object db.
Thanks in Advance

Use TypeORM repository or method on a service from outside any module

I have a nestjs app that has an AuthService which has these parts:
export class AuthService {
constructor(
#InjectRepository(User)
private readonly userRepo: Repository<User>,
) {}
async updateFromInternally () {
...
}
I have another file which is, crucially, outside of any module, which contains a number of helpful functions relating to Google oauth. For example, this file initiates Google's oauth2 client like so:
export const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
process.env.GOOGLE_CLIENT_REDIRECT
);
This file also has a listener function which I found in Google's documentation as a way to catch when my use of Google's oauth2 client automatically uses a refresh token to obtain a new access token:
oauth2Client.on('tokens', async (tokens) => {
[****]
})
At [****], I need to query in my database for a particular user and update them. Either of these conceptually work:
I somehow get userRepo into this file right here and use it to query + update
I somehow call updateFromInternally in AuthService from here
But I don't know how to interact with either TypeORM repositories or methods within services from outside of any module in nestjs! Can I do either of these?
The first question is why you're using nestjs?
You can access the internals of nestjs by using the instantiated app;
In your main.ts file you have something like this:
const app = await NestFactory.create(AppModule);
You can access the services or DataSource from the app by using the get method.
import {DataSource} from 'typeorm'
const dataSource = app.get<DataSource>(DataSource)
// or custom service
const someServices = app.get<SomeService>(SomeService)
you just need a way to export app from main.ts and import it in your outside world.
for example:
// main.ts
let app;
async bootstrap() {
app = await NestFactory.create(AppModule);
}
export const getApp = () => app;
bootstrap()
and in your other file
// outside.ts
import {getApp} from './main.ts'
const app = getApp()
I didn't write the whole logic, but I think it would give you an idea of what you need to do.
But in my opinion, it's the worst thing you can do. You're using 'nestjs` and try to respect its philosophy.
Just write a module that handles all the work you want.
I figured out #1:
import {getRepository} from "typeorm";
oauth2Client.on('tokens', async (tokens) => {
const gaRepo = getRepository(Googleauth);
// Can now use gaRepo like you do in a service
})

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

Can we use all node npm packages in Nestjs

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.

How to split Nest.js microservices into separate projects?

Let's say I want to create a simplistic cinema-management platform. It needs few microservices: movies, cinemas, payments, etc.
How would you go about doing it in Nest.js? I don't want them in the same big folder as that feels like making a monolith. I want them to be separate Nest.js projects with their own git repositories so I can orchestrate them with Kubernetes later on.
How? How to connect from service cinemas to service movies if they are two separate projects and only share, let's say, Redis?
Edit:
This is not a question about microservices in general. This is a question Nest.js specific. I read the documentation, I know there are decorators like #Client for connecting to the transport layer. I just want to know where to use that decorator and maybe see a short snippet of code on "having two separate Nest.js repositories how to connect them together so they can talk to each other".
I don't care about the transport layer, that thing I can figure out myself. I just need some advice on the framework itself as I believe the documentation is lacking.
I got it working. Basically the way to do it is to create two separate projects. Let's say - one is a createMicroservice and another is just an HTTP app (but could easily be another microservice). I used a "normal" app just so I can call it easily for testing.
Here is the main.ts file that creates microservice.
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
import { Transport } from '#nestjs/common/enums/transport.enum';
async function bootstrap() {
const app = await NestFactory.createMicroservice(AppModule, {
transport: Transport.REDIS,
options: {
url: 'redis://localhost:6379',
},
});
await app.listen(() => console.log('MoviesService is running.'));
}
bootstrap();
And one of the controllers:
#Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
#MessagePattern({ cmd: 'LIST_MOVIES' })
listMovies(): string[] {
return ['Pulp Fiction', 'Blade Runner', 'Hatred'];
}
}
Now - in the microservice you declare to what kinds of events should controllers react to (#MessagePattern). While in the "normal" service you do this in the controller when you want to ask other microservices for something (the main.ts is the simplest example that you get when you create a new project using #nestjs/cli.
The controller code:
#Controller()
export class AppController {
private readonly client: ClientProxy;
constructor(private readonly appService: AppService) {
this.client = ClientProxyFactory.create({
transport: Transport.REDIS,
options: {
url: 'redis://localhost:6379',
},
});
}
#Get()
listMovies() {
const pattern = { cmd: 'LIST_MOVIES' };
return this.client.send<string[]>(pattern, []);
}
}
So as long a client is connected to the same transport layer as the microservice - they can talk to each other by using the #MessagePattern.
For nicer code you can move the this.client part from a constructor to a provider and then use dependency injection by declaring the provider in the module.

Resources