我正在为我的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);
},
我想获得一致的输出,任何人都知道该如何解决?
答案 0 :(得分:1)
这实际上是预期的行为。
您的updateUser
和updateCity
之间的区别在于,后者返回可为空的类型(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!):用户!