在 GraphQL 查询中传递自定义变量

Posted

技术标签:

【中文标题】在 GraphQL 查询中传递自定义变量【英文标题】:Pass Custom Variables In GraphQL Query 【发布时间】:2020-07-09 07:16:09 【问题描述】:

我有一个UpdateUserPage,它可以根据传递的输入变量的数量以不同的方式调用突变,例如:

只更新名字

    mutation
            updateUser(email: "d@d.com",
            input: firstName:"check")id
            

名字和姓氏都更新了:

    mutation
            updateUser(email: "d@d.com",
            input: firstName:"check", lastName: "new")id
            

现在在我的代码中查询:

export const UPDATE_USER = gql`
  mutation UpdateUser($email: String!, $firstName: String, $lastName: String) 
    updateUser(
      email: $email
      input:  firstName: $firstName, lastName: $lastName 
    ) 
      id
      firstName
    
  
`;

我想要什么:

我想更改我的表单,如果用户只输入名字并将姓氏字段留空, 那么只有 firstName 应该被更新,这意味着应该使用第一种类型的查询,而 lastName 应该保持在调用突变之前的状态。

现在发生了什么:

例如,以前 firstName 是 HELLO,lastName 是 WORLD。现在,我将 firstName 更新为 CHECK 并将 lastName 选项留空。因此,当它返回值时,它应该将 CHECK 作为 firstName 返回,将未修改的 WORLD 作为 lastName 返回。但是,现在,它显示 lastName 为未定义。 如果我检查资源,我会看到:

"operationName":"UpdateUser","variables":"email":"c@c.com","firstName":"Final","query":"mutation UpdateUser($email: String!, $firstName: String, $lastName: String) \n updateUser(email: $email, input: firstName: $firstName, lastName: $lastName) \n id\n firstName\n __typename\n \n\n" Looks like the lastName is still being passed in the mutation.

这意味着 lastName 仍在突变中使用。所以,我需要一种将自定义变量传递到我的查询中的方法:

$input : Object!不起作用。

这是我整个页面的代码:

export default function UpdateUserPage() 
  const [isSubmitted, setIsSubmitted] = useState(false);
  const [isUpdated, setIsUpdated] = useState(false);

  const [updateUser] = useMutation(UPDATE_USER);
  let submitForm = (
    email: string,
    firstName: string,
    lastName: string,
  ) => 
    setIsSubmitted(true);

    if (email && (firstName || lastName || phoneNumber)) 
      const vars:any = 
        email
      ;
    if( firstName !== '')
      vars.firstName = firstName
      if( lastName !== '')
        vars.lastName = lastName

      updateUser(
        variables: vars)
        .then(( data : any) => 
          setIsUpdated(true);
          console.log(updateUser);
          console.log('FN: ', data.updateUser.firstName);
          console.log('LN: ', data.updateUser.lastName);
        )
        .catch((error:  message: string ) => 
          setIsUpdated(false);
        );
    
  ;

  return (
    <div>
      <Formik
        initialValues=
          firstName: '',
          lastName: '',
          email: '',
          phoneNumber: '',
        
        onSubmit=(values, actions) => 
          setTimeout(() => 
            alert(JSON.stringify(values, null, 2));
            actions.setSubmitting(false);
          , 1000);
        
        validationSchema=schema>
        props => 
          const 
            values:  firstName, lastName, email, phoneNumber ,
            errors,
            touched,
            handleChange,
            isValid,
            setFieldTouched,
           = props;
          const change = (name: string, e: FormEvent) => 
            e.persist();
            handleChange(e);
            setFieldTouched(name, true, false);
          ;
          return (
            <div className="main-content">
              <form
                style= width: '100%' 
                onSubmit=e => 
                  e.preventDefault();
                  submitForm(email, firstName, lastName);
                >
                <div>
                  <TextField
                    variant="outlined"
                    margin="normal"
                    id="email"
                    name="email"
                    helperText=touched.email ? errors.email : ''
                    error=touched.email && Boolean(errors.email)
                    label="Email"
                    value=email
                    onChange=change.bind(null, 'email')
                  />
                  <br></br>
                  <TextField
                    variant="outlined"
                    margin="normal"
                    id="firstName"
                    name="firstName"
                    helperText=touched.firstName ? errors.firstName : ''
                    error=touched.firstName && Boolean(errors.firstName)
                    label="First Name"
                    value=firstName
                    onChange=change.bind(null, 'firstName')
                  />
                  <br></br>
                  <TextField
                    variant="outlined"
                    margin="normal"
                    id="lastName"
                    name="lastName"
                    helperText=touched.lastName ? errors.lastName : ''
                    error=touched.lastName && Boolean(errors.lastName)
                    label="Last Name"
                    value=lastName
                    onChange=change.bind(null, 'lastName')
                  />
                  <CustomButton
                    text='Update User Info'
                  />
                </div>
              </form>
            </div>
          );
        
      </Formik>
    </div>
  );

编辑:

来自架构:

input: UpdateUserInput!
input UpdateUserInput 
  email: String
  firstName: String
  lastName: String
  phoneNumber: String

现在,我已经做到了:

interface UpdateUserInput 
  email: String
  firstName: String
  lastName: String
  phoneNumber: String


export const UPDATE_USER = gql`
  mutation UpdateUser($email: String!, $input : UpdateUserInput) 
    updateUser(
      email: $email
      input: $input
    ) 
      id
      firstName
    
  
`;

但是,当我提交表单时,我仍然收到此错误:

GraphQL error: The variable `input` type is not compatible with the type of the argument `input`.
Expected type: `UpdateUserInput`.

可能是因为我仍然从我的主要UpdateUserPage 传递vars。我该如何改变呢?

【问题讨论】:

【参考方案1】:

$input 变量的类型可以是 updateUser 上的 input 参数的类型。如果您不是自己编写 GraphQL 架构,则需要检查您的 API 文档或 GraphiQL/GraphQL Playground 接口以确定要使用的类型。

对每个字段使用单个变量 ($input) 而不是多个变量($firstName$lastName)是首选的处理方式。也就是说,您的查询没有任何问题。您当前的查询:

mutation ($email: String!, $firstName: String, $lastName: String) 
  updateUser(
    email: $email
    input:  firstName: $firstName, lastName: $lastName 
  )
    id
  

使用变量"email": "c@c.com", "firstName": "Final"等价于

mutation ($email: String!, $input: WhateverYourInputTypeIs) 
  updateUser(
    email: $email
    input: $input
  )
    id
  

"email": "c@c.com", "input": "firstName": "Final"

在这两种情况下,传递给服务器端解析器的参数都是相同的。如果您在突变运行后得到错误的 lastName 值,那么这就是解析器如何处理它接收到的参数的问题。

【讨论】:

感谢您为我指明正确的方向!我现在理解了类型。但是,我在我的代码中正确定义它时遇到问题?你能看到我的问题中的编辑吗?可能是一些小错误。 参数不可为空,因此您需要确保您的变量也是如此(即在类型上附加一个!)。【参考方案2】:

您可能需要修改您的界面,以便不需要这些字段。

interface UpdateUserInput 
  email?: String
  firstName?: String
  lastName?: String
  phoneNumber?: String

通过在字段中添加问号,您可以将它们设为可选,以便您一次可以传递一个或多个。

【讨论】:

以上是关于在 GraphQL 查询中传递自定义变量的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Strapi 在 GraphQL 中添加自定义查询?

如何在GraphQL中添加自定义查询?

无法将自定义结果从解析器传递到 Graphql

如何自定义 GraphQL 查询验证错误消息

解析graphql查询后实现自定义逻辑

Gatsby:在自定义帖子类型上使用 GraphQL 查询和自定义分类