typescript 为什么我的ApolloGraphQL Mutation在满足条件时没有返回错误消息?

gopyfrb3  于 2023-04-07  发布在  TypeScript
关注(0)|答案(2)|浏览(151)

这是我的第一个问题。
我已经创建了正在工作的登录/注册突变,但是,我想设置错误处理,以便当用户输入一个不正确的用户名,它返回一个错误消息“用户名不正确”,并与密码相同.
目前,当用户输入错误的用户名时会返回错误消息,但当用户输入错误的密码时不会返回。输入错误的密码会返回一个显示null用户的对象,如下所示:

{
  "data": {
    "login": {
      "user": null
    }
  }
}

我还有一个正在工作的寄存器突变,但是,当满足错误条件时,错误不会返回,它再次返回空用户。
我已经粘贴了下面的代码,登录突变是最后一个在底部。注册突变是在这上面。
谢谢你

import { User } from '../entities/User';
import { MyContext } from 'src/types';
import argon2 from 'argon2';

import {
  Resolver,
  Mutation,
  Arg,
  InputType,
  Field,
  Ctx,
  ObjectType,
  Query,
} from 'type-graphql';

@InputType()
class UsernamePasswordInput {
  @Field()
  username: string;
  @Field()
  password: string;
}

@ObjectType()
class FieldError {
  @Field()
  field: string;
  message: string;
}

@ObjectType()
class UserResponse {
  @Field(() => [FieldError], { nullable: true })
  errors?: FieldError[];

  @Field(() => User, { nullable: true })
  user?: User;
}

// SAVE USER TO DATABASE
@Resolver()
export class UserResolver {
  // GET ALL USERS

  @Query(() => [User])
  getAllUsers(@Ctx() { em }: MyContext): Promise<User[]> {
    return em.find(User, {});
  }

  @Mutation(() => UserResponse)
  async register(
    @Arg('options') options: UsernamePasswordInput,
    @Ctx() { em }: MyContext
  ): Promise<UserResponse> {
    // username
    if (options.username.length <= 2) {
      return {
        errors: [
          {
            field: 'username',
            message: 'length must be greater than 2',
          },
        ],
      };
    }
    // password
    if (options.password.length <= 3) {
      return {
        errors: [
          {
            field: 'password',
            message: 'length must be greater than 3',
          },
        ],
      };
    }
    // hash password
    const hashedPassword = await argon2.hash(options.password);
    const user = em.create(User, {
      username: options.username,
      password: hashedPassword,
    });
    await em.persistAndFlush(user);
    return {
      user,
    };
  }

  @Mutation(() => UserResponse)
  async login(
    @Arg('options') options: UsernamePasswordInput,
    @Ctx() { em }: MyContext
  ): Promise<UserResponse> {
    const user = await em.findOneOrFail(User, {
      username: options.username,
    });

    if (!user) {
      return {
        errors: [
          {
            field: 'username',
            message: ' incorrect username',
          },
        ],
      };
    }
    // verify the user password
    const valid = await argon2.verify(user.password, options.password);

    // if password is not valid, return errors
    if (!valid) {
      return {
        errors: [
          {
            field: 'password',
            message: 'incorrect password',
          },
        ],
      };
    }
    // return user
    return {
      user,
    };
  }
}
d7v8vwbk

d7v8vwbk1#

一些注意事项:

  1. JavaScript有内置的error-handling支持,请使用它。
    1.您必须遵循GraphQL ValidationApollo Server Error handling准则。
  2. TypeGraphQL通过Custom Scalarsclass-validator内置了对参数和输入验证的支持。
    有了上面的注解/假设,你的代码可以重写(和简化)如下:
    UsernamePasswordInput
// ...
import { Length } from 'class-validator'

@InputType()
class UsernamePasswordInput {
  @Field()
  @Length(3, 32) // length >= 3 and <= 32
  username: string;

  @Field()
  @Length(4, 16) // length >= 4 and <= 16
  password: string;
}

UserResolver
请注意,当检查usernamepassword时,我们利用JavaScript运算符优先级(短路)。此外,抛出的错误更通用,隐藏了可能的“明智/有用”信息,而不显示是username还是password无效。

// ...
import { AuthenticationError } from 'apollo-server-errors'

@Resolver(() => User)
class UserResolver {
  // ...

  @Mutation(() => User)
  async register(
    @Arg('data') data: UsernamePasswordInput,
    @Ctx() { em }: MyContext
  ): Promise<User> {
    // username and password length already checked

    // Hash password
    const hashedPassword = await argon2.hash(data.password);
    
    // Create user
    const user = em.create(User, {
      username: data.username,
      password: hashedPassword,
    });
    await em.persistAndFlush(user);

    // Return new user
    return user;
  }

  @Mutation(() => User)
  async login(
    @Arg('data') data: UsernamePasswordInput,
    @Ctx() { em }: MyContext
  ): Promise<User> {
    // Find user without DB error (hide information) 
    const user = await em.findOne(User, {
      username: data.username,
    });

    // Check username and password
    // Operator Precedence (Short-circuiting)
    // Generic authentication error
    if (!user ||
        !(await argon2.verify(user.password, data.password))
    ) throw new AuthenticationError("Invalid username or password");

    // ...

    // Return authenticated user
    return user;
  }
}
r7xajy2e

r7xajy2e2#

您可以使用内置的Javascript Error对象在GraphpQl变化中返回错误消息,例如

const exists = await collection.findOneQuery(itemId);

    if (!exists) {
      return new Error("Item does not exist");
    }

然后,您可以在前端检索错误消息,如下所示;

{
  "errors": [
    {
      "message": "Item does not exist",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
    
    ...
}

相关问题