无法在 GraphQL 中返回关系数据

Posted

技术标签:

【中文标题】无法在 GraphQL 中返回关系数据【英文标题】:Trouble Returning Relational Data in GraphQL 【发布时间】:2018-11-03 16:40:00 【问题描述】:

我正在创建一个 Reddit 克隆,并且我首先设置了后端,但在创建关系数据时遇到了问题。

当我使用这个查询时:

query 
  subreddit(id: 1) 
    name
    posts 
      title
    
  

我希望:


  "data": 
    "subreddit": 
      "name": "javascript"
      "posts": [
        
          "title": "JS Post"
        
      ]
    
  

我得到了什么:


  "data": null,
  "errors": [
    
      "message": "Cannot return null for non-nullable field Subreddit.posts.",
      "locations": [
        
          "line": 4,
          "column": 5
        
      ],
      "path": [
        "subreddit",
        "posts"
      ]
    
  ]

这是架构:

type Query 
  subreddits: [Subreddit!]!
  subreddit(id: ID!): Subreddit!
  posts: [Post!]!
  post(id: ID!): Post!


type Mutation 
  createSubreddit(
    name: String!
    description: String!
    contentType: String!
    ageRestriction: Boolean!
  ): Subreddit!


type Subreddit 
  id: ID!
  name: String!
  description: String!
  contentType: String!
  ageRestriction: Boolean!
  posts: [Post!]!


type Post 
  id: ID!
  title: String!
  body: String!
  subredditId: ID!
  # userId: ID!

这里是server/index.js

const  GraphQLServer  = require('graphql-yoga');

let dummySubreddits = [
  
    name: 'javascript',
    description: 'all things javascript',
    contentType: 'any',
    ageRestriction: false,
    id: 1
  ,
  
    name: 'react',
    description: 'all things react',
    contentType: 'any',
    ageRestriction: false,
    id: 2
  ,
  
    name: 'primsa',
    description: 'all things prisma',
    contentType: 'any',
    ageRestriction: false,
    id: 3
  
];
let idCountSubreddit = dummySubreddits.length;

let dummyPosts = [
   title: 'JS Post', body: 'Body of post one', id: 1, subredditId: 1 ,
   title: 'React Post', body: 'Body of post two', id: 2, subredditId: 2 ,
  
    title: 'Prisma Post',
    body: 'Body of post three',
    id: 3,
    subredditId: 3
  
];
let idCountPost = dummyPosts.length;

const resolvers = 
  Query: 
    subreddits: () => dummySubreddits,
    subreddit: (parent, args) => 
      return dummySubreddits.find(obj => obj.id == args.id);
    ,
    posts: () => (parent, args) => 
      return dummyPosts.find(obj => obj.subredditId == parent.id);
    ,
    post: (parent, args) => 
      return dummyPosts.find(obj => obj.id == args.id);
    
  ,
  Mutation: 
    createSubreddit: (parent, args) => 
      let subreddit = 
        id: idCountSubreddit++,
        name: args.name,
        description: args.description,
        contentType: args.contentType,
        ageRestriction: args.ageRestriction
      ;
      return subreddit;
    
  
;

const server = new GraphQLServer( typeDefs: './schema.graphql', resolvers );
server.start(() => console.log('Server is running on localhost:4000'));

我正在使用 GraphQL 桌面应用进行查询,但我没有 grapql-yoga 配置文件。

我哪里错了?我想指出正确的方向,以便我自己弄清楚。这是我第一次单独使用 GraphQL,在 YouTube 上做了一些教程之后,但是他们使用了graphql-express,而我正在使用graphql-yoga

【问题讨论】:

您已经显示了预期的结果,但不是您实际看到的结果,也不是您进行查询时返回的错误。看看你实际上是如何进行查询的也很好(实际的查询是什么,你是通过客户端、GraphiQL、Postman 之类的工具将它发送到服务器吗?)另外,你还没有包括你的解析器或者你的 graphql-yoga 配置 @DanielRearden 哦,我忘了补充。我将编辑问题以包含它。我正在使用 GraphQL 桌面 app。我已经包括了解析器。它们在const resolvers = ... 里面,它在server/index.js 里面。我没有配置文件。 我的意思是你应该包括你如何配置你的GraphQLServer 实例:) 【参考方案1】:

将您为Queryposts 编写的解析器移动到Subreddit 以解析那里的帖子字段。如果您的解析器不符合默认的解析器实现:

(parent) => parent[fieldName]

就像你的情况

(parent) => parent.posts

您必须自己指定。如果您在 Query 上的字段 posts 应该显示所有您可能想要针对以下实现的帖子:

const resolvers = 
  Query: 
    subreddits: () => dummySubreddits,
    subreddit: (parent, args) => 
      return dummySubreddits.find(obj => obj.id == args.id);
    ,
    posts: () => dummyPosts,
    post: (parent, args) => 
      return dummyPosts.find(obj => obj.id == args.id);
    
  ,
  Subreddit: 
    posts: () => (parent, args) =>
      dummyPosts.filter(obj => obj.subredditId == parent.id),
  ,
  Mutation: 
    createSubreddit: (parent, args) => 
      let subreddit = 
        id: idCountSubreddit++,
        name: args.name,
        description: args.description,
        contentType: args.contentType,
        ageRestriction: args.ageRestriction
      ;
      return subreddit;
    
  
;

【讨论】:

你是对的。这就是问题所在。一位朋友想通了,但无论如何感谢您抽出宝贵时间提供帮助!【参考方案2】:

我必须为subreddit 添加一个解析器来处理posts

const resolvers = 
  Query: 
    subreddits: () => dummySubreddits,
    subreddit: (parent, args) => 
      return dummySubreddits.find(obj => obj.id == args.id);
    ,
    posts: (parent, args) => 
      return dummyPosts;
    ,
    post: (parent, args) => 
      return dummyPosts.find(obj => obj.id == args.id);
    
  ,
  Mutation: 
    createSubreddit: (parent, args) => 
      let subreddit = 
        id: idCountSubreddit++,
        name: args.name,
        description: args.description,
        contentType: args.contentType,
        ageRestriction: args.ageRestriction
      ;
      return subreddit;
    
  ,

  // This resolver was needed
  Subreddit: 
    posts: subreddit =>
      dummyPosts.filter(obj => obj.subredditId == subreddit.id)
  
;

【讨论】:

以上是关于无法在 GraphQL 中返回关系数据的主要内容,如果未能解决你的问题,请参考以下文章

我们如何从 GraphQL 的 RequestContextHolder 获取 GraphQL 的 HttpServletRequest(DefaultGlobalContext)(使用 graphq

如何对graphQL中的字段进行运行时数据操作?

Apollo GraphQL:用于查询返回不同类型对象的模式?

带有官方 Graphql 教程的“无法在 CreateUser 类型上查询字段 'id'”

API 平台 GraphQL 关系中的安全性

使用 Mongoose 和 graphql-yoga 实现分页