Search code examples
javascriptnestjsjoi

Nested object in Joi schema


I've defined validation schema via Joi with nested object in AWS value:

const schema = Joi.object({
  NODE_ENV: Joi.string()
    .valid('development', 'production', 'test')
    .default('development'),
  PORT: Joi.number().default(3000),
  AWS: Joi.object({
    accessKeyId: Joi.string().required(),
    secretAccessKey: Joi.string().required(),
    region: Joi.string().required(),
    bucket: Joi.string().required(),
  }).required(),
});

Then I put my schema to config module

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      validationSchema: schema,
      validationOptions: {
        abortEarly: false,
        cache: false,
      },
    }),
    FilesModule,
    UsersModule,
    PostsModule,
    SharedModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

I've added inside .env file the next value for AWS variable:

AWS={"region": "string", "accessKeyId":"string", "secretAccessKey": "string", "bucket": "string"}

but I got the next error message after starting nest:

> project-8v@0.0.1 start /Volumes/MacDATA/NestJs/project-8v
> nest start


/Volumes/MacDATA/Lern/NestJs/project-8v/node_modules/@nestjs/config/dist/config.module.js:66
                throw new Error(`Config validation error: ${error.message}`);
                      ^
Error: Config validation error: "AWS" must be of type object

typeof process.env.AWS returns a string and Joi doesn't understand that he should parse it, maybe I need to add some in validationOptions or I miss something. How can I solve it?


Solution

  • As of Joi v16.0.0, object and array string coercion is no longer available as a built-in option.

    You can replicate this functionality by extending Joi. For example:

    const JoiCustom = Joi.extend({
      type: 'object',
      base: Joi.object(),
      coerce: {
        from: 'string',
        method(value) {
          if (value[0] !== '{' && !/^\s*{/.test(value)) {
            return {
              value
            };
          }
          try {
            return { value: JSON.parse(value) };
          } catch (error) {
            return {
              errors: [error]
            };
          }
        }
      }
    });
    

    Then use JoiCustom in your schema:

    const schema = Joi.object({
        ...
        AWS: JoiCustom.object({
            ...
        }).required()
    });