Skip to content

Commit 068a659

Browse files
Merge branch 'LeoAnesi-docs/config-add-documentation-for-validate-function'
2 parents 9c8554f + b6c07d1 commit 068a659

File tree

1 file changed

+67
-4
lines changed

1 file changed

+67
-4
lines changed

content/techniques/configuration.md

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,13 +183,13 @@ interface EnvironmentVariables {
183183
constructor(private configService: ConfigService<EnvironmentVariables>) {
184184
// this is valid
185185
const port = this.configService.get<number>('PORT');
186-
186+
187187
// this is invalid as URL is not a property on the EnvironmentVariables interface
188188
const url = this.configService.get<string>('URL');
189189
}
190190
```
191191

192-
> warning **Notice** If you have nested properties in your config, like in the `database.host` example above, the interface must have a matching `'database.host': string;` property. Otherwise a TypeScript error will be thrown.
192+
> warning **Notice** If you have nested properties in your config, like in the `database.host` example above, the interface must have a matching `'database.host': string;` property. Otherwise a TypeScript error will be thrown.
193193
194194
#### Configuration namespaces
195195

@@ -256,9 +256,12 @@ export class DatabaseModule {}
256256
257257
#### Schema validation
258258

259-
It is standard practice to throw an exception during application startup if required environment variables haven't been provided or if they don't meet certain validation rules. The `@nestjs/config` package enables use of the [Joi](https://github.com/hapijs/joi) npm package to support this type of validation. With Joi, you define an object schema and validate JavaScript objects against it.
259+
It is standard practice to throw an exception during application startup if required environment variables haven't been provided or if they don't meet certain validation rules. The `@nestjs/config` package enables two different ways to do this:
260+
261+
- [Joi](https://github.com/hapijs/joi) built-in validator. With Joi, you define an object schema and validate JavaScript objects against it.
262+
- A custom `validate()` function which takes environment variables as an input.
260263

261-
Install Joi (and its types, for **TypeScript** users):
264+
To use Joi, we must install Joi package (and its types, for **TypeScript** users):
262265

263266
```bash
264267
$ npm install --save @hapi/joi
@@ -322,6 +325,66 @@ The `@nestjs/config` package uses default settings of:
322325

323326
Note that once you decide to pass a `validationOptions` object, any settings you do not explicitly pass will default to `Joi` standard defaults (not the `@nestjs/config` defaults). For example, if you leave `allowUnknowns` unspecified in your custom `validationOptions` object, it will have the `Joi` default value of `false`. Hence, it is probably safest to specify **both** of these settings in your custom object.
324327

328+
#### Custom validate function
329+
330+
Alternatively, you can specify a **synchronous** `validate` function that takes an object containing the environment variables (from env file and process) and returns an object containing validated environment variables so that you can convert/mutate them if needed. If the function throws an error, it will prevent the application from bootstrapping.
331+
332+
In this example, we'll proceed with the `class-transformer` and `class-validator` packages. First, we have to define:
333+
334+
- a class with validation constraints,
335+
- a validate function that makes use of the `plainToClass` and `validateSync` functions.
336+
337+
```typescript
338+
@@filename(env.validation)
339+
import { plainToClass } from 'class-transformer';
340+
import { IsEnum, IsNumber, validateSync } from 'class-validator';
341+
342+
enum Environment {
343+
Development = "development",
344+
Production = "production",
345+
Test = "test",
346+
Provision = "provision",
347+
}
348+
349+
class EnvironmentVariables {
350+
@IsEnum(Environment)
351+
NODE_ENV: Environment;
352+
353+
@IsNumber()
354+
PORT: number;
355+
}
356+
357+
export function validate(config: Record<string, unknown>) {
358+
const validatedConfig = plainToClass(
359+
EnvironmentVariables,
360+
config,
361+
{ enableImplicitConversion: true },
362+
);
363+
const errors = validateSync(validatedConfig, { skipMissingProperties: false });
364+
365+
if (errors.length > 0) {
366+
throw new Error(errors.toString());
367+
}
368+
return validatedConfig;
369+
}
370+
```
371+
372+
With this in place, use the `validate` function as a configuration option of the `ConfigModule`, as follows:
373+
374+
```typescript
375+
@@filename(app.module)
376+
import { validate } from './env.validation';
377+
378+
@Module({
379+
imports: [
380+
ConfigModule.forRoot({
381+
validate,
382+
}),
383+
],
384+
})
385+
export class AppModule {}
386+
```
387+
325388
<app-banner-shop></app-banner-shop>
326389

327390
#### Custom getter functions

0 commit comments

Comments
 (0)