- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个graphql
/ apollo-server
/ graphql-yoga
端点。该端点公开从数据库(或REST端点或其他服务)返回的数据。
我知道我的数据源正在返回正确的数据-如果将调用结果记录到解析器中的数据源,则可以看到正在返回的数据。但是,我的GraphQL字段始终解析为null。
如果我使该字段为非空,则在响应中的errors
数组内会看到以下错误:
无法为不可为空的字段返回null
为什么GraphQL不返回数据?
最佳答案
您的一个或多个字段解析为null的常见原因有两个:1)返回解析器内部形状错误的数据;和2)没有正确使用Promises。
注意:如果您看到以下错误:
无法为不可为空的字段返回null
根本的问题是您的字段返回null。您仍然可以按照以下概述的步骤尝试解决此错误。
以下示例将引用此简单模式:
type Query {
post(id: ID): Post
posts: [Post]
}
type Post {
id: ID
title: String
body: String
}
data
对象的“形状”。形状是指对象具有的属性,以及这些属性的值是标量值,其他对象还是对象或标量的数组。
post
字段中,我们返回值
{ title: 'My First Post', bod: 'Hello World!' }
。如果我们不为
Post
类型的任何字段编写解析器,我们仍然可以请求
post
:
query {
post {
id
title
body
}
}
{
"data": {
"post" {
"id": null,
"title": "My First Post",
"body": null,
}
}
}
title
字段,因为默认的解析程序进行了繁重的工作-它看到父字段的Object字段上有一个名为
title
的属性(在本例中为
post
字段解析为null,因为我们在
id
解析器中返回的对象没有
post
属性。由于输入错误,
id
字段也解析为null -我们有一个名为
body
的属性,而不是
bod
!
body
不是拼写错误,而是API或数据库实际返回的内容,我们总是可以为
bod
字段编写一个解析器以匹配我们的模式。例如:
body
(parent) => parent.bod
字段解析为字符串或数字,则
post
类型上的每个字段的默认解析器仍将尝试在父对象上查找适当命名的属性,不可避免地失败并返回null。如果字段具有对象类型,但是在其解析程序中返回的对象不是对象(例如String或Array),则不会看到有关类型不匹配的任何错误,但该字段的子字段将不可避免地解析为null。
Post
查询编写解析器,则可能会从其他端点获取代码,如下所示:
function post (root, args) {
// axios
return axios.get(`http://SOME_URL/posts/${args.id}`)
.then(res => res.data);
// fetch
return fetch(`http://SOME_URL/posts/${args.id}`)
.then(res => res.json());
// request-promise-native
return request({
uri: `http://SOME_URL/posts/${args.id}`,
json: true
});
}
post
字段的类型为
post
,因此我们的解析器应返回具有
Post
,
id
和
title
之类的属性的对象。如果这是我们的API返回的结果,那么我们都准备就绪。但是,通常将响应实际上是包含其他元数据的对象。因此,我们实际上从端点返回的对象可能看起来像这样:
{
"status": 200,
"result": {
"id": 1,
"title": "My First Post",
"body": "Hello world!"
},
}
body
,
id
和
title
属性。我们的解析器不需要执行以下操作:
function post (root, args) {
// axios
return axios.get(`http://SOME_URL/posts/${args.id}`)
.then(res => res.data.result);
// fetch
return fetch(`http://SOME_URL/posts/${args.id}`)
.then(res => res.json())
.then(data => data.result);
// request-promise-native
return request({
uri: `http://SOME_URL/posts/${args.id}`,
json: true
})
.then(res => res.result);
}
body
对象,该对象包含
Result
,
rows
,
fields
和
rowCount
之类的属性。您需要先从此响应中提取适当的数据,然后再将其返回到解析器中。
function post(root, args, context) {
return context.Post.find({ where: { id: args.id } })
}
command
是我们通过上下文注入的某种模型。如果使用的是
Post
,则可以调用
sequelize
。
findAll
和
mongoose
具有
typeorm
。这些方法的共同之处在于,尽管它们允许我们指定
find
条件,但它们返回的Promise仍然解析为数组而不是单个对象。虽然数据库中可能只有一个帖子具有特定ID,但是当您调用这些方法之一时,它仍被包装在数组中。因为数组仍然是对象,所以GraphQL不会将
WHERE
字段解析为null。但是它将所有子字段解析为null,因为它将无法在数组上找到适当命名的属性。
function post(root, args, context) {
return context.Post.find({ where: { id: args.id } })
.then(posts => posts[0])
}
post
),该方法将显式地仅从数据库返回一行(如果不存在,则返回null)。
function post(root, args, context) {
return context.Post.findOne({ where: { id: args.id } })
}
findOne
和
INSERT
调用的特别说明:我们通常希望插入或更新行或模型实例的方法返回插入或更新的行。他们经常这样做,但是有些方法却没有。例如,
UPDATE
的
sequelize
方法解析为布尔值,或者是加高后的记录和布尔值的元组(如果
upsert
选项设置为true)。
returning
的
mongoose
解析为具有
findOneAndUpdate
属性的对象,其中包含修改后的行。在将其返回到解析器之前,请查阅您的ORM文档并适当地解析结果。
value
字段的类型是
posts
的
List
,这意味着其解析器需要返回对象数组(或解析为一个的Promise)。我们可能会这样获取帖子:
function posts (root, args) {
return fetch('http://SOME_URL/posts')
.then(res => res.json())
}
{
"count": 10,
"next": "http://SOME_URL/posts/?page=2",
"previous": null,
"results": [
{
"id": 1,
"title": "My First Post",
"body" "Hello World!"
},
...
]
}
function posts (root, args) {
return fetch('http://SOME_URL/posts')
.then(res => res.json())
.then(data => data.results)
}
Post
),也可以返回将解析为该值的Promise。对于具有
{ id: 1, title: 'Hello!' }
类型的字段,您还可以返回一个Promises数组。如果Promise拒绝,则该字段将返回null,并且相应的错误将添加到响应中的
List
数组。如果字段具有对象类型,则Promise解析为的值将作为父值向下传递给任何子字段的解析器。
errors
函数。该函数的实现细节并不重要-只是返回Promise的函数,该函数将解析为post对象。
getPost
字段的有效解析器可能如下所示:
function post(root, args) {
return getPost(args.id)
}
post
返回一个Promise,我们返回该Promise。无论Promise决定解决什么,它将成为我们领域解决的价值。看起来不错!
function post(root, args) {
getPost(args.id)
}
getPosts
语句的JavaScript函数中,将隐式返回
return
。因此,我们的函数创建一个Promise,然后立即返回
undefined
,使GraphQL为该字段返回null。
undefined
返回的Promise拒绝,我们在响应中也不会看到任何错误-因为我们没有返回Promise,所以底层代码并不关心它是解决还是拒绝。实际上,如果Promise拒绝,您将在服务器控制台中看到
getPost
。
UnhandledPromiseRejectionWarning
。
return
的调用结果,因此您将解析器更改为如下所示:
function post(root, args) {
return getPost(args.id)
.then(post => {
console.log(post)
})
}
getPost
时,我们实际上是在使用Promise解析的值并返回一个新的Promise。您可以想到它类似于
then
,但Promises除外。
Array.map
可以返回一个值或另一个Promise。无论哪种情况,在
then
内部返回的内容都“链接”到原始Promise上。可以通过使用多个
then
将多个Promise链接在一起。链中的每个Promise都是按顺序解决的,最终值就是有效地解析为原始Promise的值。
then
内未返回任何内容,因此Promise解析为
then
,GraphQL将其转换为null。要解决此问题,我们必须退回帖子:
function post(root, args) {
return getPost(args.id)
.then(post => {
console.log(post)
return post // <----
})
}
undefined
并返回正确的值来正确地链接它们。例如,如果需要在调用
then
之前调用其他两个异步函数(
getFoo
和
getBar
),则可以执行以下操作:
function post(root, args) {
return getFoo()
.then(foo => {
// Do something with foo
return getBar() // return next Promise in the chain
})
.then(bar => {
// Do something with bar
return getPost(args.id) // return next Promise in the chain
})
getPost
的
mongoose
方法:
function post(root, args) {
return Post.findOne({ where: { id: args.id } }, function (err, post) {
return post
})
findOne
不会返回Promise。它只是返回未定义。在此示例中,我们的回调将被调用,如果我们记录
Post.findOne
的值,我们将看到从数据库返回的任何内容。但是,因为我们没有使用Promise,所以GraphQL不会等待此回调完成-它使用返回值(未定义)并使用它。
post
支持开箱即用。那些不经常使用免费的“包装”库来添加此功能的库。使用GraphQL解析器时,应避免使用利用回调的方法,而应使用返回Promises的方法。
function post(root, args) {
return new Promise((resolve, reject) => {
Post.findOne({ where: { id: args.id } }, function (err, post) {
if (err) {
reject(err)
} else {
resolve(post)
}
})
})
关于graphql - 为什么GraphQL查询返回null?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56319137/
我有三张 table 。表 A 有选项名称(即颜色、尺寸)。表 B 有选项值名称(即蓝色、红色、黑色等)。表C通过将选项名称id和选项名称值id放在一起来建立关系。 我的查询需要显示值和选项的名称,而
在mysql中,如何计算一行中的非空单元格?我只想计算某些列之间的单元格,比如第 3-10 列之间的单元格。不是所有的列...同样,仅在该行中。 最佳答案 如果你想这样做,只能在 sql 中使用名称而
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 7 年前。 Improve this ques
我正在为版本7.6进行Elasticsearch查询 我的查询是这样的: { "query": { "bool": { "should": [ {
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 7 年前。 Improve this ques
是否可以编写一个查询来检查任一子查询(而不是一个子查询)是否正确? SELECT * FROM employees e WHERE NOT EXISTS (
我找到了很多关于我的问题的答案,但问题没有解决 我有表格,有数据,例如: Data 1 Data 2 Data 3
以下查询返回错误: 查询: SELECT Id, FirstName, LastName, OwnerId, PersonEmail FROM Account WHERE lower(PersonEm
以下查询返回错误: 查询: SELECT Id, FirstName, LastName, OwnerId, PersonEmail FROM Account WHERE lower(PersonEm
我从 EditText 中获取了 String 值。以及提交查询的按钮。 String sql=editQuery.getText().toString();// SELECT * FROM empl
我有一个或多或少有效的查询(关于结果),但处理大约需要 45 秒。这对于在 GUI 中呈现数据来说肯定太长了。 所以我的需求是找到一个更快/更高效的查询(几毫秒左右会很好)我的数据表大约有 3000
这是我第一次使用 Stack Overflow,所以我希望我以正确的方式提出这个问题。 我有 2 个 SQL 查询,我正在尝试比较和识别缺失值,尽管我无法将 NULL 字段添加到第二个查询中以识别缺失
什么是动态 SQL 查询?何时需要使用动态 SQL 查询?我使用的是 SQL Server 2005。 最佳答案 这里有几篇文章: Introduction to Dynamic SQL Dynami
include "mysql.php"; $query= "SELECT ID,name,displayname,established,summary,searchlink,im
我有一个查询要“转换”为 mysql。这是查询: select top 5 * from (select id, firstName, lastName, sum(fileSize) as To
通过我的研究,我发现至少从 EF 4.1 开始,EF 查询上的 .ToString() 方法将返回要运行的 SQL。事实上,这对我来说非常有用,使用 Entity Framework 5 和 6。 但
我在构造查询来执行以下操作时遇到问题: 按activity_type_id过滤联系人,仅显示最近事件具有所需activity_type_id或为NULL(无事件)的联系人 表格结构如下: 一个联系人可
如何让我输入数据库的信息在输入数据 5 分钟后自行更新? 假设我有一张 table : +--+--+-----+ |id|ip|count| +--+--+-----+ |
我正在尝试搜索正好是 4 位数字的 ID,我知道我需要使用 LENGTH() 字符串函数,但找不到如何使用它的示例。我正在尝试以下(和其他变体)但它们不起作用。 SELECT max(car_id)
我有一个在 mysql 上运行良好的 sql 查询(查询 + 连接): select sum(pa.price) from user u , purchase pu , pack pa where (
我是一名优秀的程序员,十分优秀!