Skip to content

Commit bbec0d4

Browse files
committed
Provide hook for IDs to be transformed/resolved within the validation layer
1 parent f399a95 commit bbec0d4

File tree

5 files changed

+58
-28
lines changed

5 files changed

+58
-28
lines changed

src/common/id.arg.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { PipeTransform, Type } from '@nestjs/common';
22
import { Args, ArgsOptions, ID as IdType } from '@nestjs/graphql';
3-
import { ValidateIdPipe } from './validators';
3+
import { ValidateIdPipe } from './validators/short-id.validator';
44

55
export const IdArg = (
66
opts: Partial<ArgsOptions> = {},

src/common/validators/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export * from './email.validator';
22
export * from './iana-timezone.validator';
33
export * from './iso-3166-1-alpha-3.validator';
4-
export * from './short-id.validator';
4+
export { IsId } from './short-id.validator';

src/common/validators/short-id.validator.ts

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,54 @@
1-
import { ArgumentMetadata, PipeTransform } from '@nestjs/common';
2-
import { ValidationOptions } from 'class-validator';
1+
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';
2+
import {
3+
ValidationArguments,
4+
ValidationOptions,
5+
ValidatorConstraint,
6+
ValidatorConstraintInterface,
7+
} from 'class-validator';
38
import { ValidationException } from '~/core/validation';
49
import { isValidId } from '../generate-id';
10+
import { ID } from '../id-field';
511
import { ValidateBy } from './validateBy';
612

713
export const IsId = (validationOptions?: ValidationOptions) =>
8-
ValidateBy(
9-
{
10-
name: 'IsId',
11-
validator: {
12-
validate: isValidId,
13-
defaultMessage: () =>
14-
validationOptions?.each
15-
? 'Each value in $property must be a valid ID'
16-
: 'Invalid ID',
17-
},
18-
},
19-
validationOptions,
20-
);
14+
ValidateBy(ValidIdConstraint, {
15+
message: validationOptions?.each
16+
? 'Each value in $property must be a valid ID'
17+
: 'Invalid ID',
18+
...validationOptions,
19+
});
20+
21+
@Injectable()
22+
export class IdResolver {
23+
async resolve(value: ID): Promise<ID> {
24+
return value;
25+
}
26+
}
27+
28+
@Injectable()
29+
@ValidatorConstraint({ name: 'IsId', async: true })
30+
export class ValidIdConstraint implements ValidatorConstraintInterface {
31+
constructor(private readonly resolver: IdResolver) {}
2132

33+
async validate(value: unknown, args: ValidationArguments) {
34+
if (isValidId(value)) {
35+
(args.object as any)[args.property] = await this.resolver.resolve(value);
36+
return true;
37+
}
38+
return false;
39+
}
40+
}
41+
42+
@Injectable()
2243
export class ValidateIdPipe implements PipeTransform {
44+
constructor(private readonly resolver: IdResolver) {}
45+
2346
transform(id: unknown, metadata: ArgumentMetadata) {
24-
if (id == null || isValidId(id)) {
25-
return id;
47+
if (id == null) {
48+
return null;
49+
}
50+
if (isValidId(id)) {
51+
return this.resolver.resolve(id);
2652
}
2753
throw new ValidationException([
2854
{

src/components/changeset/changeset.arg.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,10 @@ import {
77
import { Args, ArgsOptions, ID as IDType } from '@nestjs/graphql';
88
import { Resolver } from '@nestjs/graphql/dist/enums/resolver.enum.js';
99
import { RESOLVER_TYPE_METADATA as TypeKey } from '@nestjs/graphql/dist/graphql.constants.js';
10-
import {
11-
ID,
12-
InputException,
13-
ServerException,
14-
ValidateIdPipe,
15-
} from '../../common';
16-
import { createAugmentedMetadataPipe } from '../../common/augmented-metadata.pipe';
17-
import { ResourceLoader } from '../../core';
10+
import { ID, InputException, ServerException } from '~/common';
11+
import { createAugmentedMetadataPipe } from '~/common/augmented-metadata.pipe';
12+
import { ValidateIdPipe } from '~/common/validators/short-id.validator';
13+
import { ResourceLoader } from '~/core/resources';
1814

1915
const pipeMetadata = createAugmentedMetadataPipe<{
2016
mutation: boolean;
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
import { Module } from '@nestjs/common';
22
import { APP_PIPE } from '@nestjs/core';
33
import { Validator } from 'class-validator';
4+
import {
5+
IdResolver,
6+
ValidateIdPipe,
7+
ValidIdConstraint,
8+
} from '~/common/validators/short-id.validator';
49
import { ValidationPipe } from './validation.pipe';
510

611
@Module({
712
providers: [
813
Validator,
914
ValidationPipe,
1015
{ provide: APP_PIPE, useExisting: ValidationPipe },
16+
ValidIdConstraint,
17+
ValidateIdPipe,
18+
IdResolver,
1119
],
12-
exports: [ValidationPipe],
20+
exports: [ValidationPipe, ValidateIdPipe, IdResolver],
1321
})
1422
export class ValidationModule {}

0 commit comments

Comments
 (0)