How to setup different environment file in nest js using postgresql - nestjs

I am new this framework. I connected PostgreSQL database using ormconfig file. but I need to configure development environment, production environment, test environment. How to achieve this scenarios. I tried to use config service in my project. but always connected only .env file configuration.
development.env
POSTGRES_HOST=127.0.0.1
POSTGRES_PORT="5432"
POSTGRES_USER=postgres
POSTGRES_PASSWORD='*****'
POSTGRES_DATABASE=testdb123
PORT=4000

You could use ormconfig.js and at the top of it add something like this:
require('dotenv').config({
path: '.env.' + process.env.NODE_ENV
})
Another option is to import ConfigModule like this:
ConfigModule.forRoot({
load: [config],
envFilePath: '.env.' + process.env.NODE_ENV
})
And use async configuration for TypeORM:
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
type: 'mysql',
host: configService.get('POSTGRES_HOST'),
port: +configService.get<number>('POSTGRES_PORT'),
username: configService.get('POSTGRES_USER'),
password: configService.get('POSTGRES_PASSWORD'),
database: configService.get('POSTGRES_DATABASE'),
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: configService.get('TYPEORM_SYNC'),
}),
inject: [ConfigService],
})
I use a similar async configuration here.

Well, I would recomment to keep .env file under git ignore and have a .env.example with all possible configuration items.
If you like to have a default settings for every env, you can use something like
https://www.npmjs.com/package/dotenv-defaults
If you want to use DI & typing as well as env files for each environments, take a look at the nest configuration module

Related

Cant access variables from .env file in node.js application

I am trying to dockerize a strapi app with mongodb atlas database. The issue I am facing is that database file in /config is not reading the variable from .env file.
.env file
HOST=0.0.0.0
PORT=1337
DATABASE_HOST=xyz.mongodb.net
DATABASE_USERNAME=abc-admin
DATABASE_PASSWORD=12345xyz
ADMIN_JWT_SECRET=abcd1234
Database connection code
const {
DATABASE_HOST,
DATABASE_USERNAME,
DATABASE_PASSWORD
} = process.env;
module.exports = ({ env }) =>
({
defaultConnection: 'default',
connections: {
default: {
connector: 'mongoose',
settings: {
host: env('DATABASE_HOST', process.env.DATABASE_HOST),
srv: env.bool('DATABASE_SRV', true),
port: env.int('DATABASE_PORT', 27017),
database: env('DATABASE_NAME', 'xyz-dev'),
username: env('DATABASE_USERNAME', process.env.DATABASE_USERNAME),
password: env('DATABASE_PASSWORD', process.env.DATABASE_PASSWORD)
},
options: {
authenticationDatabase: env('AUTHENTICATION_DATABASE', null),
ssl: env.bool('DATABASE_SSL', true),
},
},
},
});
I have tried with process.env and without it in the above file. But when I run the image after build it shows below error
error Error connecting to the Mongo database. URI does not have
hostname, domain name and tld
Any idea what I am doing wrong here? Thanks
One option is to use dotenv you need to import dotenv and run dotenv.config() before you can start using env variables
so change to
import dotenv from "dotenv";
dotenv.config()
// your code which user process.env
other option is to define all those env variable on your OS level. On unix you can add to ~/.bashrc file
Here's a bit more elaborate answer to your question (after reading your comments). Creating .env file means you just created it. It doesn't get automatically loaded. It's a typical way to use on unix machines, but has no relation to Node whatsoever.
What you need to do is somehow parse the content of that file (which is purely text), convert it to key-value pairs and pass it to node. There are many packages, and one that Amit showed is dotenv. It does all the work for you, and at the end, you get your variables injected inside process.env.
The simplest way would be to install this package (from npm) and use it as described. But if you cannot modify the code in any way, then you can simply parse the content of the file with a script, and then start the node server. Here's an example (taken from npm scripts: read .env file):
"scripts": {
"example": "some-lib --argument --domain $(grep DOMAIN .env | cut -d '=' -f2)"
}
The drawback here is that it doesn't work across various operating systems and that using a specific library for that is way more tested than your manual scripts.

How to run TypeORM migrations command on AWS Elastic Beanstalk

I'm writing node.js applications using nest.js and typeORM. I put everything on AWS Elastic Beanstalk and there is no problem here, the API works properly.
I wrote two migrations in typeORM and it's time to run the typeorm migrations: run command on the production database. I was looking for help, solutions, tips, but I couldn't find anything specific.
I started to try to set up a second Elastic Beanstalk instance with the code, only instead of the node main command I will want to run typeorm migrations: run.
This is probably not the best solution, so I am asking you for help. Maybe someone knows how to do it correctly?
The best solution to run your migrations on your production server is to set migrationsRun to true in your database configuration.
This will avoid you to run manually the migration command, It will be done automatically on start.
migrationsRun: true
Here is an example to use it in your database configuration:
return {
type: 'postgres',
host: process.env.POSTGRES_HOST,
port: +process.env.POSTGRES_PORT,
username: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
database: process.env.POSTGRES_DB,
entities:
process.env.NODE_ENV === 'test'
? ['src/**/*.entity.ts']
: ['dist/**/*.entity{.ts,.js}'],
synchronize: false,
migrationsRun: true,
migrations:
process.env.NODE_ENV === 'test'
? ['src/core/database/migrations/**/*.ts']
: ['dist/core/database/migrations/**/*.js'],
cli: {
migrationsDir: 'src/core/database/migrations',
},
};

newrelic/apollo-server-plugin with NEST.JS

I am using NEST.JS framework and want to add external plugin New Relic Apollo Server plugin.
apollo-server-fastify: "^2.19.2"
#newrelic/apollo-server-plugin: "^0.1.2"
import { apolloServerNewRelicPlugin } from '#newrelic/apollo-server-plugin';
GraphQLModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
....
plugins: [apolloServerNewRelicPlugin],
}),
When I start server for e2e test it required real NewRelic key ; is there a way to start for test environment without requiring real key ?
To test out things I started server with real key; Missing Key and cannot start agent error disappeared but below is the error I am seeing
UnhandledPromiseRejectionWarning: TypeError: Cannot use 'in' operator to search for '__internal_plugin_id__' in undefined
my-application | at Object.pluginIsInternal (/usr/src/app/node_modules/apollo-server-fastify/node_modules/apollo-server-core/dist/plugin/internalPlugin.js:5:37)
Update: the plugin has been updated and it supports TypeScript now.
I've had the same error initially. The way I made it work here was to create a typings/newrelic-apollo-server-plugin/index.ts file containing a module declaration:
declare module '#newrelic/apollo-server-plugin'
Then, in my NestJS module file:
import apolloServerNewRelicPlugin from '#newrelic/apollo-server-plugin'
#Module({
imports: [
...
GraphQLModule.forRoot({
...
plugins: [apolloServerNewRelicPlugin],
}),

in nodejs app how to use dotenv and config?

I am new to development, i understand that dotenv create environment variables that we don't want to expose in our code , while config create similar variables to be used by app for configuration however I am little confused about use case. could you explain it a little or point me to further resource for better understanding. and is there any other similar packages that create environment variables and how are they used ?
The way I do it is using both dotenv and config packages.
You'd create a .env file (which you'll add to .gitignore)
For example
client_id='1234'
client_secret='XXXXX'
Then you create a folder called config at the root of your project, and inside it a file default.js
In this file you'll add first
require('dotenv').config();
and then you can export js friendly variables
require('dotenv').config();
export const client = {
clientId: process.env.client_id,
clientSecret: process.env.client_secret
}
Finally you can use these in your index.ts for example
import config from 'config';
console.log(config.get('client'));
// { clientId: '1234', clientSecret: 'XXXXX'}
You can use dotenv npm package for this use case
create a .env file in your project something similar to:
DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3
then you can configure your file:
const dotenv = require('dotenv');
dotenv.config({ path: path.resolve(__dirname, './config.env') })
then you can use them like:
db.connect({
host: process.env.DB_HOST,
username: process.env.DB_USER,
password: process.env.DB_PASS
})

Why my TypeORM can't connect database in product mode?

I am using Nest.js+TypeORM to develop and try to deploy in my computer.
I can connect to mysql in develop mode, but it failed in product mode.
Below is my TypeORM config.
#Module({
imports: [
AuthModule,
ClassificationModule,
ArticleModule,
UserModule,
CommentModule,
FragmentModule,
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
// logging: ["query"],
port: 3306,
username: 'root',
password: '123456',
database: 'myblog',
entities: ['src/**/**.entity{.ts,.js}'],
synchronize: true
})
]
})
export class AppModule { }
In develop mode, it can connect to mysql successfully.
But in product mode, it shows can't connect mysql.
ts-node manages your typescript compilation in memory and handles chaning references from src to dist internally. However, this is a problem when you get into running your pure node variant, as you'll be in a dist directory instead of src, so TypeORM won't be able to find your entities with the defined entities array. Instead you should use entities: [join(__dirname, '/**/*.entity.{js,ts}')], to allow for dynamically changing between ts and js so you don't have to worry about what you are running with.
I would also suggest using tsc-watch for develpoment, as it will run node by default on successful compilation and you won't have to worry about memory consumption from ts-node.

Resources