Graphql / Apollo错误有时输出数据:null有时数据输出:{function:null}

时间:2019-04-27 16:26:22

标签: node.js graphql graphql-js apollo-server

我正在为我的graphql设置测试。在这样做的同时,我意识到有时错误情况下的数据对象输出如下:

public function hookDisplayHeader()
{
        return  '<style type="text/css">.popup { position:fixed; width: 350px; height: 650px; bottom:0; right: 0; z-index:1000}</style>
        <!-- Matomo -->
        <script type="text/javascript">
          var _paq = window._paq || [];
          /* tracker methods like "setCustomDimension" should be called before "trackPageView" */
          _paq.push(['trackPageView']);
          _paq.push(['enableLinkTracking']);
          (function() {
            var u="//stats.xxx.com/";
            _paq.push(['setTrackerUrl', u+'matomo.php']);
            _paq.push(['setSiteId', '1']);
            var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
            g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
          })();
        </script>
        <!-- End Matomo Code -->        
        ';
}

有时:

{
   errors: [...],
   data: null
}

这些测试是针对突变的。这是两个代码的示例:

解析器案例1:

{
     errors: [...],
     data: {
        updateCity: null
    }
}

模式案例1:

 updateUser(parent, args, context, info) {
      logger.debug('Mutation > updateUser resolver');
      return userController.user.update.user(parent, args.userInfo, context, info);
    },

控制器案例1:

extend type Mutation {
    updateUser(userInfo: UserInfo!): User!
}

模式案例2:

user: async (parent, args, context, info) => {
    try {
      logger.debug('User Controller : update User');
      await controller.validate(args);
      const userModel = new UserModel('member');
      if (!(await userModel.findOne(args.id))) errorscb.userInputError('User does not exist');
      let id = args.id;
      let newArgs = args;
      delete newArgs.id;
      return userModel.updateById(id, newArgs);
    } catch (e) {
      logger.warn({ stack: e.stack, message: e.message });
      throw e;
    }
  },

解析器案例2:

extend type Mutation {

    updateCity(id: Int!, name: String, countryId: Int): City
}

控制器案例2:

updateCity(obj, args, context, info) {
      logger.info('City > updateCity resolver');
      return cityController.city.update.city(obj, args, context, info);
    },

我想获得一致的输出,任何人都知道该如何解决?

2 个答案:

答案 0 :(得分:1)

这实际上是预期的行为。

您的updateUserupdateCity之间的区别在于,后者返回可为空的类型(City),而前者则返回非空类型(User! )。响应之间的差异来自以下事实:错误会传播到响应中,直到它们到达可为空的字段为止。来自spec

  

如果解析字段时抛出错误,则应将其视为字段返回null,并且必须在响应的“错误”列表中添加错误。

     

如果解析字段的结果为null(由于解析字段的函数返回null或发生错误),并且该字段属于Non-Null类型,则抛出字段错误。该错误必须添加到响应的“错误”列表中。

     

...

     

由于非null类型的字段不能为null,因此传播字段错误以由父字段处理。如果父字段可能为null,则解析为null;否则,如果它是Non-Null类型,则该字段错误会进一步传播到其父字段。

换句话说,通过在字段解析期间抛出错误,我们可以将该字段有效地解析为null。但是,当我们告诉GraphQL某个字段具有Non-Null类型,并且该字段解析为null时,GraphQL无法返回带有null值的字段(因为这会破坏模式的约定)。因此,它会使整个 parent 字段为空。如果父字段也是不可为空的,它将使该字段的父字段为空,依此类推,直到到达可空字段或请求的根(data字段)为止。

比较:模式1

type Query {
  a: A
}

type A {
  b: B
}

type B {
  c: String
}

模式2

type Query {
  a: A
}

type A {
  b: B
}

type B {
  c: String!
}

模式3

type Query {
  a: A!
}

type A {
  b: B!
}

type B {
  c: String!
}

如果我们请求字段c和字段c的解析程序引发,则响应如下:

模式1

{
  "data": {
    "a": {
      "b": {
        "c": null
      }
    }
  }
}

模式2

{
  "data": {
    "a": {
      "b": null
    }
  }
}

模式3

{
  "data": null
}

答案 1 :(得分:0)

extend type Mutation {
    updateUser(userInfo: UserInfo!): User!
}

找到了解决方法,要求用户没有必要,并且删除了感叹号,从而解决了我的问题(嗯。。。)

updateUser(userInfo:UserInfo!):用户