0
votes

I have custom scalars for my users ID, CustomerID and ProviderID, I would like to validate them when someone call a mutation to ensure that the given ID match a user and of correct type.

We cannot make CustomerScalar parseValue method asynchronous, so I'm looking for a nice way to deal with such things.

Maybe customerDecorator ? I don't know ? Any idea ? I would like to access my repository using Dependencies Injection to ensure that the passed ID exists in the database and is really a Customer. Field Middleware and Directive seems not to support Deps injection.

@InputType()
export class CreateBillInput {
  @Field(() => CustomerIDScalar)
  customerID: CustomerID;

  @Field()
  name: string;

  @Field(() => Int)
  amount: number;
}

What I wanted that cannot work :

@Injectable()
export class CustomerIDScalar implements CustomScalar<string, CustomerID> {
  constructor(private userRepository: IUserRepository) {}

  parseValue(value: string) {
    return this.getCustomerID(value);
  }

  parseLiteral(ast: ValueNode) {
    if (ast.kind !== Kind.STRING) {
      throw new TypeError('Argument is not a string value.');
    }

    return this.getCustomerID(value);;
  }

  serialize(value: CustomerID) {
    return value.value; // value sent to the client
  }

  // TODO: Not usable here
  private async getCustomerID(userID: string): Promise<CustomerID> {
    const user = await this.userRepository.getByID(userID);

    if (!user || !user.isCustomer()) {
      throw new BadRequestException('There is no such customer user for provided ID.');
    }

    return user.id as CustomerID;
  }
}

Thanks

1

1 Answers

0
votes

First of all. gql scalars validation are about technical check to validate all data are correct (schema check). It's not suppose to have any business rules validation stuff there.

To achieve desired result you can use the next things:

  1. Nest validation pipes with @Args decorator:

    @Mutation(returns => Group) async createGroup( @Args('group', new ValidationPipe()) input: CreateGroupInput, )

  2. class-validation https://github.com/typestack/class-validator

  3. Simply put a regular ID/Int scalar for the input type & validate it later in service class that responsive for such operation (recommend to use this approach for such things in gql)