我已经在带有GraphQL API的NestJS服务器上使用React和Apollo客户端制作了简单的CRUD应用。
我有这个简单的突变:
schema.gql:
type Mutation {
createUser(input: CreateUserInput!): User! // CreateUserInput type you can see in user.input.ts below
updateUser(id: ID!, input: UpdateUserInput!): User!
deleteUser(id: ID!): User!
}
user.input.ts:
import { InputType, Field } from "@nestjs/graphql";
import { EmailScalar } from "../email.scalar-type";
@InputType()
export class CreateUserInput {
// EmailScalar is a custom Scalar GraphQL Type that i took from the internet and it worked well
@Field(() => EmailScalar)
readonly email: string;
@Field()
readonly name: string;
}
“ EmailScalar”类型检查“电子邮件”输入是否基本上具有*@*.*
格式
当我像这样对GraphQL API进行createUser查询时:
It cannot pass validation (因为电子邮件类型可以正常工作)
但是当客户端发送查询时-它通过了验证:
NestJS server log(来自下面的代码)
users.resolver.ts:
@Mutation(() => User)
async createUser(@Args('input') input: CreateUserInput) { // Type from user.input.ts
Logger.log(input); // log from screenshot, so if it's here it passed validation
return this.usersService.create(input); // usersService makes requests to MongoDB
}
这是客户端部分:
App.tsx:
...
// CreateUserInput class is not imported to App.tsx (it is at server part) but it seems to be fine with it
const ADD_USER = gql`
mutation AddMutation($input: CreateUserInput!) {
createUser(input: $input) {
id
name
email
}
}
`
function App(props: any) {
const { loading, error, data } = useQuery(GET_USERS);
const [addUser] = useMutation(
ADD_USER,
{
update: (cache: any, { data: { createUser } }: any) => {
const { users } = cache.readQuery({ query: GET_USERS });
cache.writeQuery({
query: GET_USERS,
data: {
users: [createUser, ...users],
},
})
}
}
);
...
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return <UserTable users={data.users} addUser={addUser} updateUser={updateUser} deleteUser={deleteUser} />;
}
有人可以向我解释一下,客户端查询如何通过验证,我做错了什么?
两个空字符串都可以通过。
以前从未使用过NestJS,Apollo,React或GraphQL,所以我有点迷茫。
答案 0 :(得分:1)
这是定义自定义标量方法的方式:
parseValue(value: string): string {
return value;
}
serialize(value: string): string {
return value;
}
parseLiteral(ast: ValueNode): string {
if (ast.kind !== Kind.STRING) {
throw new GraphQLError('Query error: Can only parse strings got a: ' + ast.kind, [ast]);
}
// Regex taken from: http://stackoverflow.com/a/46181/761555
var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
if (!re.test(ast.value)) {
throw new GraphQLError('Query error: Not a valid Email', [ast]);
}
return ast.value;
}
解析查询内部的文字值(即用双引号引起来的文字字符串)时,会调用 parseLiteral
。解析变量值时调用parseValue
。当您的客户端发送查询时,它将值作为变量而不是文字值发送。因此,使用parseValue
代替parseLiteral
。但是您的parseValue
不会进行任何形式的验证-您只按原样返回值。您需要在两种方法中都使用验证逻辑。
实现serialize
方法也是一个好主意,这样您的标量可以用于输入和响应验证。