对于 Rails 和 GraphQL 项目,如何定义多个同名查询?

Posted

技术标签:

【中文标题】对于 Rails 和 GraphQL 项目,如何定义多个同名查询?【英文标题】:For a Rails and GraphQL project, how do you define multiple queries with the same name? 【发布时间】:2020-01-21 18:55:07 【问题描述】:

这里有一些上下文:我使用的是 Rails 5.1.4、Ruby 2.6.1 和 GraphQL 1.9。我的 Rails 项目当前配置为仅 REST api 项目。但是,我开始将其转换为使用 GraphQL。运行graphql相关的生成器后,我目前有一个graphql_controller.rb文件和一个query_type.rb文件。

对于我的数据库模型,我有一个 SchoolCourse 模型,它描述了大学教授的特定课程。对于这个模型,我定义了一个school_course_type.rb。在我的query_type.rb 文件中,我为schoolCourse 查询定义了一个字段。

但是,有两种类型的用户可以登录我的应用程序 - 教师和学生。如果用户是教师,则访问应用程序并查询schoolCourse 将返回该特定教师教授的所有学校课程。如果用户是学生,则访问应用程序并查询schoolCourse 将返回该特定学生参加的所有学校课程。在这两种情况下,schoolCourse 数据都是同一类型 (school_course_type)。

我目前有query_type.rb 中定义的schoolCourse 查询为教师工作。但是,如果我想扩展 schoolCourse 查询也适用于学生,我似乎必须更新 schoolCourse 查询以包含 if / else 逻辑,看起来像这样:

# This is how it currently looks like:

def schoolCourses
  teacher_user = context[:current_user]
  teacher_user.school_courses
end


# This is how I think it would change:

def schoolCourses
  user = context[:current_user]

  if user.type == 'teacher'
    user.school_courses
  else
    # different way for students to retrieve school courses
  end
end

虽然这可能有效,但这并不理想。 我要解决的主要问题是定义多个schoolCourse 查询并设置它,以便教师使用一个版本,学生使用另一个版本。

在我当前的应用程序中,我有 2 个schoolCourse 控制器 - 一个用于教师,一个用于学生,通过将其拆分为两个文件,我的 API 更加简洁。 有什么方法可以对 query_type.rb 文件执行类似操作,其中我有一个 query_type 供教师使用,另一个供学生使用?您是如何在项目中处理这个问题的?

添加更多上下文 - 太平洋标准时间 2019 年 9 月 20 日下午 2:10

    如何区分学生和教师的学校课程? 因此,学生和教师的学校课程对象是相同的。目前在我的 RESTful 后端中,我有 2 个单独的控制器文件用于获取学生课程。一个是给老师的,另一个是给学生的。当教师的学校课程控制器被调用时,它只会为登录的教师返回学校课程。同样,当调用学生的学校课程控制器时,它只会返回登录学生的学校课程。

    您能详细说明为什么要查询多个学校课程吗? 我之所以想查询多个学校课程是因为我不想在单个学校课程查询中添加 if / else 逻辑,为教师做一些事情,为学生做一些事情。我知道它会起作用,但我可能还有 50 个其他模型,而且我不必在每个查询中放入相同类型的 if / else 逻辑。

【问题讨论】:

【参考方案1】:

需要更多关于学校课程如何区分学生和教师的信息。您能否详细说明为什么要查询多个学校课程?

您可以使用接口定义:

类型将变成如下所示:

module Types
  module Output
    StudentCourse = GraphQL::ObjectType.define do
      name "StudentCourse"

      interfaces [CourseInterface]

      field :student_specific_field, Types::Output::SpecificField

    end
  end
end

module Types
  module Output
    TeacherCourse = GraphQL::ObjectType.define do
      name "TeacherCourse"

      interfaces [CourseInterface]

      field :teacher_specific_field, Types::Output::SpecificField

    end
  end
end

module Types
  module Output
    CourseInterface = GraphQL::InterfaceType.define do
      name "Course"

      resolve_type lambda  |context, obj, _|
        case context[:user].type?
        when student
          Types::Output::StudentCourse
        when teacher
          Types::Output::TeacherCourse
        else
          raise Types::CantResolveType, "can't resolve type: #obj.class"
        end
      

      field :id, !types.ID
    end
  end
end

【讨论】:

感谢 Tanay 的回复 - 我继续并根据您的问题在我的初始帖子中添加了更多上下文。让我知道上下文是否有助于提出解决方案。 我喜欢这个响应,除了定义不同的类型,如果基础模型/模式是相同的,无论是学生还是教师。如果模式相同,您实际上是在要求返回同一个表中的不同记录。这对我来说归结为 SQL 查询中的 where 子句或课程模型上的 Active Record 范围。如果您有不同的课程模型表明这些领域是不同的,这进一步表明它们是不同的课程类型,我只会使用不同的类型

以上是关于对于 Rails 和 GraphQL 项目,如何定义多个同名查询?的主要内容,如果未能解决你的问题,请参考以下文章

graphql_devise 用于 Rails/Graphql/Apollo/React 中的身份验证。 “字段需要身份验证”错误

如何在 Rails 中设置 GraphQL Relay API

无法将 GraphQL 查询从 Apollo 客户端发送到 Rails GraphQL 后端

在GraphQL / Rails中如何在query_type中传递参数?

Rails、Graphql、Apollo 客户端的 Auth Token 无效

如何在 Rails 4 中指定asset_host?