通过服务器端验证进行中继突变

时间:2016-08-01 19:07:40

标签: graphql relayjs

我正在尝试编写一个允许服务器端验证的中继突变。例如具有该名称的记录已经存在。

以下是我的GraphQL变异。

/* @flow weak */
import {mutationWithClientMutationId,offsetToCursor} from "graphql-relay";
import {GraphQLString, GraphQLList, GraphQLNonNull} from "graphql";
import NominationConnection from '../NominationsConnection';
import ViewerType from '../../../types/ViewerType';
import Helper from '../../../helper/helper';
import Nomination from '../../../model/Nomination';


const mongo = require('mongodb');

/**
 * mutationWithClientMutationId()
 *
 * This helper function helps us create Relay-compliant GraphQL mutations it takes an object with the following params
 * { name: "", inputField: { }, outputFields: {},  mutateAndGetPayload: function({}) }
 *
 */
export default mutationWithClientMutationId({

  // Name of the Mutation
  name: "Nomination_Add",

  // Describes the fields that should be used when invoking the mutation
  inputFields: {
    name: {
      type: new GraphQLNonNull(GraphQLString)
    },
    description: {
      type: new GraphQLNonNull(GraphQLString)
    },
    books: {
      type: new GraphQLList(GraphQLString)
    }

  },

  // response that will be sent back when the mutation is complete
  outputFields: {
    NominationsEdge: {
      type: NominationConnection.edgeType,
      resolve: ( {local_id}, { ...args }, context, { rootValue: objectManager } ) =>
      {
        //RT: local_id is the object that was inserted into DB.;
        let nomination = local_id[0];
        console.log("nomination: ", nomination);
        if(nomination.Errors.length > 0){

          return objectManager.getListBy('Nomination', nomination, {}, {})
              .then((arr) => {

                return ( {
                  cursor: null,
                  node: nomination,
                } )
              })
        }else {

          let an_Object;
          return objectManager.getOneByParam('Nomination', nomination, {_id: nomination.id})
              .then((retrieved_Object) => {


                an_Object = retrieved_Object;

              })

              .then(() => objectManager.getListBy('Nomination', an_Object, {}, {}, objectManager.getViewerUserId()))
              .then((arr) => {


                return ( {
                  cursor: Helper.cursorForObjectInConnection(arr, an_Object, "id"),
                  node: an_Object,
                } )
              })
              ;
        }
      }
    },

    Viewer: {
      type: ViewerType,
      resolve: (parent, args, context, {rootValue: objectManager}) => objectManager.getOneById('User', objectManager.getViewerUserId())
    }
  },

  mutateAndGetPayload: ({name, description, books}, context, {rootValue: objectManager}) => {
    if(!books){
      books = [];
    }

    return objectManager.add('Nomination', {
      name,
      description,
      books
    }, {name: name}).then((local_id) => ( {local_id} ));
  }
});

以下是我的接力突变。

/* @flow weak */

import Relay from 'react-relay';

export default class Nomination_addMutation extends Relay.Mutation {
  // static fragments = {
  //   Viewer: () => Relay.QL`
  //     fragment on Viewer {
  //       id,
  //     }
  //   `,
  // };
  getMutation() {

    return Relay.QL`mutation{Nomination_Add}`;
  }
  getFatQuery() {


    return Relay.QL`
      fragment on Nomination_AddPayload {
      NominationsEdge,
        Viewer {
         Nominations(first:500){
         edges{
          node{
             id,
            Name,
            Description
            }
          }
         }
        }
      }
    `;
  }
  getConfigs() {

    return [{
      type: 'RANGE_ADD',
      parentName: 'Viewer',
      parentID: this.props.Viewer.id,
      connectionName: 'Nominations',
      edgeName: 'NominationsEdge',
      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',
      },
    }];
  }
  getVariables() {

    return {

      name: this.props.name,
      description: this.props.description,
      books: this.props.books,
    };
  }
  getOptimisticResponse() {


    return {
      Nomination: {

        name: this.props.name,
        description: this.props.description,
        books: this.props.books,

    },
      Viewer: {
      id: this.props.Viewer.id,
    },
    };
  }
}

以下是我如何致电它。

 Relay.Store.commitUpdate(
        new Nomination_Add( {name: fields.name , description: fields.desc ,Viewer:this.props.Viewer}),
          {
            onSuccess: response => {
             console.log(response);
              console.log(response.Nomination_Add);
            },
          }
      );

我的响应对象只有Viewer.id和clientmuationID。当我通过graphql调用此突变时,它看起来像这样。

mutation{
  Nomination_Add(input:{name:"test", description:"test", clientMutationId:"2"}){
  NominationsEdge{
    node{
      Name,
      Description,
    Errors {
      Message
    }
      Books{
        Title
      }
    }
  }
  }

}

对此作出回应。

{
  "data": {
    "Nomination_Add": {
      "NominationsEdge": {
        "node": {
          "Name": "test",
          "Description": "test",
          "Errors": [
            {
              "Message": "Nomination Already Exists"
            }
          ],
          "Books": []
        }
      }
    }
  }
}

如何通过中继将服务器验证错误消息发送回客户端来编写逻辑?

也试过这个作为我的胖查询

 return Relay.QL`
      fragment on Nomination_AddPayload {
      NominationsEdge {
        node{
            Errors {
              Message
            }
          }
        },
        Viewer {
         Nominations(first:500){
         edges{
          node{
             id,
            Name,
            Description
            }
          }
         }
        }
      }
    `;

响应如下:

{,…}
data
:
{Nomination_Add: {clientMutationId: "0", Viewer: {id: "00000000-0000-0000-0000-000000000000"}}}
Nomination_Add
:
{clientMutationId: "0", Viewer: {id: "00000000-0000-0000-0000-000000000000"}}
Viewer
:
{id: "00000000-0000-0000-0000-000000000000"}
id
:
"00000000-0000-0000-0000-000000000000"
clientMutationId
:
"0"

2 个答案:

答案 0 :(得分:0)

您没有收到服务器端验证错误消息,因为您没有告诉Relay您想要它们。看看你的GraphiQL变异和你的中继突变的胖查询。您在前者中包含Homestead.yml,但在后者中不包括。

在您的中继变异(Errors)胖查询中包含Errors,如下所示:

Nomination_addMutation

答案 1 :(得分:0)

我可以在mutateAndGetPayload上抛出一个错误:这将作为错误消息发送到突变的onFailure回调,错误信息就是我抛出的内容。

  mutateAndGetPayload: ({name, description, books}, context, {rootValue: objectManager}) => {
    if(!books){
      books = [];
    }

    return objectManager.add('Nomination', {
      name,
      description,
      books
    }, {name: name}).then((nominations) => {

      //RT: readability
    let nomination = nominations[0];

      //RT: if Mongo id is not assigned.
      // No records where created.
         if(nomination.id == null)
          throw nomination.Errors[0].Message;

      return ( {nomination}

      )});
  }

这似乎不是正确的方法。有没有人见过更好的例子?

编辑:清理代码并决定基于这些示例执行此操作。似乎不对。

https://medium.com/@fcpgate/i-think-what-eslam-mentioned-is-more-on-the-right-track-cdd07519bf97#.na73ulbxj(阅读评论。)

https://facebook.github.io/relay/docs/api-reference-relay-store.html

http://stackoverflow.duapp.com/questions/37044914/how-to-tackle-server-side-input-validation-using-relay?rq=1

https://github.com/facebook/relay/issues/696