Hello folks! I’m starting out this tutorial series related to NestJS and RavenDB with topics such as configuration, repository pattern, indexes or entities, maybe even a bit of MVC with Handlebars as templating engine. I really enjoy working with this stack, it quickly became my favorite one out there. I particularly like how it’s organized, the pace that I manage to produce high quality code, security and integrations.
So this series of tutorials is addressed to whom wants to learn more about the NestJS and RavenDB stack (RavenNest). A developer background is needed to tackle all the concepts. All the source code can be found on my Github project page. The codebase that I used at the start of this tutorial series is located in the tutorial-initial branch.
Default NestJS config with .env file
Today we are going to kick off with NestJS config which is important to setup in the beginning phases of development. NestJS has built-in configuration management via the @nestjs/config npm package and it’s really easy to use. Moreover, it’s very easy to change the configuration source which is what we want to achieve in this tutorial. What I don’t like in the default implementation is that it uses .env files, specifically in our case:
RAVEN_SERVER=http://localhost:8080
RAVEN_DATABASE=raven-nest
As you can notice, settings in environment variables files are straightforward but frugal as well. My recommendation is to store them in YAML files because it’s more organized and it’s easier to have different data types like numbers, booleans or even arrays. The YAML file that we will use onwards looks like this:
environment: 'development'
names:
- Will
- Bob
- Chris
db:
raven:
database: 'raven-nest'
url: 'http://localhost:8080/'
Making YAML magic in NestJS
Ok, let’s start the implementation of this new NestJS config. First of all, we need to create the config.yml file in our project and add the content from above:
Secondly, we require to install the js-yaml npm package, which provides support for YAML file handling:
yarn add js-yaml
Once this is complete, we will need to add a new module inside src folder called app-config. This will be loaded by the main module of the app and it will load our new config file. After that, we can inject the built-in ConfigService to access the defined settings exactly like before.
The file src/app-config/configuration.ts would look like this:
import { readFileSync } from 'fs';
import * as yaml from 'js-yaml';
import { join } from 'path';
const YAML_CONFIG_FILENAME = 'conf/config.yml';
export default () => {
return yaml.load(
readFileSync(join(YAML_CONFIG_FILENAME), 'utf8'),
) as Record<string, any>;
};
This is the code that loads the YAML configuration and returns the Javascript object representation of it. Next to it we have the index.ts module declaration which basically tells NestJS where to get this new configuration from. This is how the configuration module looks like:
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import configuration from './configuration';
@Module({
imports: [
ConfigModule.forRoot({
ignoreEnvFile: true,
load: [configuration],
isGlobal: true,
})
],
exports: [],
})
export class AppConfigModule { }
All we have to do now is to import it in our AppModule:
@Module({
imports: [
AppConfigModule,
],
controllers: [AppController],
providers: [AppService, RavendbService],
})
export class AppModule {}
Important: remove any other ConfigModule.forRoot calls inside the app.module.ts as now AppConfigModule takes care of it and it’s no longer necessary.
Testing it out
Magic magic, but who believes in magic if there is no proof? 😁 By the way, you will need to change the key names for the settings in a similar manner like below:
Allright, let’s proceed by creating an endpoint which will return us the values of the settings defined in our config.yml, environment and names respectively. Be wary that names is an array and we will return it as such. To achieve this, first we need to inject the ConfigService in the app.controller.ts constructor:
constructor(
private readonly appService: AppService,
private readonly ravenService: RavendbService,
private readonly config: ConfigService) {}
Now the last thing to do is to add the actual endpoint:
@Get('config')
getConfig() {
const environment = this.config.get<string>('environment');
const names = this.config.get<string[]>('names');
return { environment, names };
}
This basically gets the values from the settings and returns them to the client. Notice the type specification on the config.get method, which tells what kind of variable we are looking for. This is an array in the case of the names key.
You can now go to http://localhost:3000/app/config and check that the values from the settings are correctly returned to the user:
{
"environment": "development",
"names": [
"Will",
"Bob",
"Chris"
]
}
Well there you go, this is a proof that magic works 🙂
Conclusion
Besides magic that works, we can conclude that configuring a NestJS app is easy and tweak-able. I’m pretty sure it can be expanded to a database as well, maybe it’s worth to explore.
Thanks for reading, I hope you found this article useful and interesting. If you have any suggestions don’t hesitate to contact me. If you found my content useful please consider a small donation. Any support is greatly appreciated! Cheers 😉