【问题标题】:How to tackle server-side input validation using Relay?如何使用 Relay 处理服务器端输入验证?
【发布时间】:2016-08-30 21:44:29
【问题描述】:

我有以下有效的 GraphQL 操作:

GraphQL 突变:

mutation CreateUserMutation ($input: CreateUserInput!) {
  createUser(input: $input) {
    clientMutationId
    userEdge {
      node {
        email
        username
      }
    },
    validationErrors {
      id
      email
    }
  }
}

GraphQL 突变响应:

{
  "data": {
    "createUser": {
      "clientMutationId": "112",
      "userEdge": {
        "node": {
          "email": "prasath112@example.com",
          "username": "soosap112"
        }
      },
      "validationErrors": {
        "id": "create-user-validation-errors",
        "email": [
          "Email looks not so good."
        ]
      }
    }
  }
}

到目前为止一切顺利,我的 GraphQL 响应的 validationErrors 是键值对的对象,其中 value 始终是来自服务器的输入验证错误消息数组特定的输入字段(即{'email': ['email is taken', 'email is on blacklist']})。

下一步(这是我需要帮助的地方)-如何在 Relay 客户端存储中使用该数据?换句话说,要如何让我的组件中的 validationErrors 成为this.props.validationErrors

CreateUserMutation.js

import Relay from 'react-relay';

export class CreateUserMutation extends Relay.Mutation {
  getMutation() {
    return Relay.QL`
      mutation {
        createUser
      }
    `;
  }

  getVariables() {
    return {
      email: this.props.email,
      username: this.props.username,
      password: this.props.password,
    };
  }

  getFatQuery() {
    return Relay.QL`
      fragment on CreateUserPayload @relay(pattern: true) {
        userEdge,
        validationErrors,
        viewer { userConnection }
      }
    `;
  }

  getConfigs() {
    return [
      {
        type: 'FIELDS_CHANGE',
        fieldIDs: {
          validationErrors: 'create-user-validation-errors',
        },
      },
      {
        type: 'RANGE_ADD',
        parentName: 'viewer',
        parentID: this.props.viewer.id,
        connectionName: 'userConnection',
        edgeName: 'userEdge',
        rangeBehaviors: {
          // When the ships connection is not under the influence
          // of any call, append the ship to the end of the connection
          '': 'append',
          // Prepend the ship, wherever the connection is sorted by age
          // 'orderby(newest)': 'prepend',
        },
      },
    ];
  }
}

这是我的尝试:首先,我可以使用 getConfigs RANGE_ADDuser edge 消耗到我的 Relay 客户端存储中。由于我的validationErrors 对象没有实现连接模型,所以FIELDS_CHANGE 在我的例子中似乎是唯一合理的类型。我正在尝试模拟 Relay 似乎需要使用“create-user-validation-errors”作为唯一 ID 填充客户端存储的 dataID

这是我的 React 组件中的一个 sn-p,用于使示例完整。

class App extends React.Component {
  static propTypes = {
    limit: React.PropTypes.number,
    viewer: React.PropTypes.object,
    validationErrors: React.PropTypes.object,
  };

  static defaultProps = {
    limit: 5,
    validationErrors: {
      id: 'create-user-validation-errors',
    },
  };

  handleUserSubmit = (e) => {
    e.preventDefault();

    Relay.Store.commitUpdate(
      new CreateUserMutation({
        email: this.refs.newEmail.value,
        username: this.refs.newUsername.value,
        password: this.refs.newPassword.value,
        viewer: this.props.viewer,
      })
    );
  };

  • 如何使用 Relay 从 React 组件中的 GraphQL 响应中使用基于非连接模型的信息片段?最小的工作示例会很棒。

  • 您知道使用 GraphQL 和 Relay 进行服务器端输入验证的更好方法吗?

【问题讨论】:

    标签: relayjs


    【解决方案1】:

    突变要么成功,要么失败。我通常设计客户端突变的胖查询和配置,牢记成功案例。处理失败的情况,mutation 的回调函数就足够了。

    如何使用 Relay 从 React 组件中的 GraphQL 响应中使用基于非连接模型的信息?

    据我所知,有两种方法

    1) 使用FIELDS_CHANGE 输入客户端突变代码的getConfigs 函数: 当我们需要更新Relay store 中的数据以响应突变的结果时,通常使用这个。代码如下所示:

    getFatQuery() {
      return Relay.QL`
        fragment on CreateUserPayload {
          ...
          ...
          viewer { 
            userCount,
          }
        }
      `;
    }
    
    getConfigs() {
      return [
        {
          type: 'FIELDS_CHANGE',
          fieldIDs: {
            viewer: this.props.viewer.id,
          },
        },
        ...
        ...
      ];
    }
    

    在您的情况下,如果您想将 validationErrors 作为 Relay 存储的一部分进行更新,请将其作为道具传递并拥有 validationErrors: this.props.validationErrors.id

    2) 使用突变的回调函数: 当我们只需要一些不应该影响 Relay 存储中数据的信息时,这是一个不错的选择。代码如下:

    const mutation = new CreateUserMutation({
      email: this.state.email,
      username: this.state.username,
      password: this.state.password,
      viewer: this.props.viewer,
    });
    const onSuccess = (response) => {
      // If you have both successful data update and some other extra info, you
      // can have, say `response.warnings`. The server sends `warnings` in the
      // response object.
    };
    const onFailure = (transaction) => {
      // This is the most appropriate place for dealing with errors.
      var error = transaction.getError();
      // Get the errors!
    };
    Relay.Store.commitUpdate(mutation, {onSuccess, onFailure});
    

    您知道使用 GraphQL 和 Relay 进行服务器端输入验证的更好方法吗?

    GraphQL 和 Relay 支持的基本输入验证目前仅限于使用 GraphQLNonNull 和预期类型,例如 names: new GraphQLNonNull(GraphQLString)。因此,如果我们为 name 传递一个整数,则突变将失败并提供相应的错误消息。

    对于其他类型的验证,服务器端突变中的mutateAndGetPayload 函数是一个好地方,我们可以在其中应用自己的逻辑。

    Konstantin Tarkus 在 GraphQL 突变中的输入验证上有 an excellent article

    【讨论】:

    • 嘿,这正是我想要的——感谢您的澄清。我已阅读引用的文章。 Tarkus 区分系统级错误和应用程序级错误。 系统级错误可以在onFailure回调中很好地处理,应用级错误应该在mutateAndGetPayload中处理——这就是我从中得到的。
    • @soosap 找到了一个 npm 模块 graphql-errors,它为客户端屏蔽了 GraphQL 系统级别 错误。我自己没用过。认为您可能感兴趣。
    • transaction.getError() 是否返回对象?
    • @maxwell: 是的,transaction.getError() 返回一个像 {"source":{"data":{"mutation_name":null},"errors":[{"message":"error_message_thrown_in_server","locations":[{"line":1,"column":68}]}]}} 这样的对象
    • 阅读github.com/facebook/relay/issues/777 似乎@soosap 解决方案更好,他可以使用查询配置REQUIRED_CHILDREN 然后与响应有效负载进行交互
    猜你喜欢
    • 2017-10-14
    • 1970-01-01
    • 1970-01-01
    • 2016-02-06
    • 2021-12-13
    • 1970-01-01
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多