TL;DR
How to group decorators (from a library) together into 1 re-usable decorator
The Problem
Every time my REST API receives a request, it will validate the provided body properties (using the class-validator library). Every route has its own dedicated validation class (in the code they are called Dtos) (see example)
Every provided body property has a couple of validation rules, these can sometimes get really complex, other engineers should be able to re-use these validation rules easily.
Example
Route 1: Company Creation
POST - /api/company
>> Parameters: name, domain, size, contact
class CreateCompanyDto implements Dto {
@IsString({message: 'Must be text format'})
@MinLength(2, { message: "Must have at least 2 characters" })
@MaxLength(20, { message: "Can't be longer than 20 characters" })
@IsDefined({ message: 'Must specify a receiver' })
public name!: string;
@MaxLength(253, { message: "Can't be longer than 253 characters" })
@IsFQDN({}, {message: 'Must be a valid domain name'})
@IsDefined({ message: 'Must specify a domain' })
public domain!: string;
@MaxLength(30, { message: "Can't be longer than 30 characters" })
@IsString({message: 'Must be text format'})
@IsDefined({ message: 'Must specify a company size' })
public size!: string;
@IsPhoneNumber(null, {message: 'Must be a valid phone number'})
@IsDefined({ message: 'Must specify a phone number' })
public contact!: string;
}
Route 2: Company Update
PUT - /api/company
>> Parameters: id, name, domain, size, contact
class UpdateCompanyDto implements Dto {
@IsUUID()
@IsDefined({ message: 'Must be defined' })
public id!: string;
@IsString({ message: 'Must be text format' })
@MinLength(2, { message: "Must have at least 2 characters" })
@MaxLength(20, { message: "Can't be longer than 20 characters" })
@IsOptional()
public name!: string;
@MaxLength(253, { message: "Can't be longer than 253 characters" })
@IsFQDN({}, { message: 'Must be a valid domain name' })
@IsOptional()
public domain!: string;
@MaxLength(30, { message: "Can't be longer than 30 characters" })
@IsString({ message: 'Must be text format' })
@IsOptional()
public size!: string;
@IsPhoneNumber(null, { message: 'Must be a valid phone number' })
@IsOptional()
public contact!: string;
}
What I'm searching for
Like you can see in the example, it's not uncommon that one validation class need to use properties from another validation class.
The problem is that if an engineer adds 1 validation rule to a property inside a random validation class, the other validation classes won't dynamically update.
Question: What is the best way to make sure that once a decorator gets changed/added other validation classes know about the update.
Is there some way to group them together into a variable/decorator? Any help from any Typescript guru is appreciated!
Acceptable outcome:
class CreateCompanyDto implements Dto {
@IsCompanyName({required: true})
public name!: string;
@IsCompanyDomain({required: true})
public domain!: string;
@isCompanySize({required: true})
public size!: string;
@isCompanyContact({required: true})
public contact!: string;
}
class UpdateCompanyDto implements Dto {
@IsCompanyId({required: true})
public id!: string;
@IsCompanyName({required: false})
public name!: string;
@IsCompanyDomain({required: false})
public domain!: string;
@isCompanySize({required: false})
public size!: string;
@isCompanyContact({required: false})
public contact!: string;
}