如何在 Rails 中设置 GraphQL 中继 API

How to setup a GraphQL Relay API in Rails

我正在努力思考 GraphQL/Relay,但我发现很难开始了解如何使用 Ruby 在 Rails.

我找到了多个关于如何执行此操作的教程:

https://medium.com/react-weekly/relay-facebook-on-rails-8b4af2057152#.gd8p6tbwi

https://medium.com/@gauravtiwari/graphql-and-relay-on-rails-getting-started-955a49d251de#.m05xjvi82

但是他们都指的是 graphql-relay gem 目前似乎不可用:https://github.com/rmosolgo/graphql-relay-ruby

grahql-ruby gem 在文档中有一个特定于 relay 的部分,但我发现很难理解将其设置为由中继客户端。

在 Rails 中为 Relay 客户端实现 GraphQL API 需要什么?

你试过安装吗?

vagrant$ bundle install
Fetching gem metadata from https://rubygems.org/............
Fetching version metadata from https://rubygems.org/...
Fetching dependency metadata from https://rubygems.org/..
Resolving dependencies...
Installing graphql 0.19.4
Using bundler 1.11.2
Installing graphql-relay 0.12.0
Bundle complete! 1 Gemfile dependency, 3 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.

在 Gemfile 中:

gem 'graphql-relay'

我只想将我的发现留在这里,以供将来遇到此问题并希望指明更好方向的任何人。

首先,graphql-ruby gem 包含实现 Relay 兼容 GraphQL API 所需的一切。其中包括 graphql-relay gem.

之前的所有内容

您需要在 Schema 中提供 2 个东西才能使 Relay refetching 功能正常工作,一个 id_from_object 将域中的对象转换为全局 ID 的方法,以及一个 object_from_id 将全局 ID 解码为应用程序中对象的方法:

ApplicationSchema = GraphQL::Schema.define do
  /* Create IDs by joining the type name & ID, then base64-encoding it */
  id_from_object ->(object, type_definition, query_ctx) {
    GraphQL::Schema::UniqueWithinType.encode(type_definition.name, object.id)
  }

  object_from_id ->(id, query_ctx) {
    type_name, object_id = GraphQL::Schema::UniqueWithinType.decode(id)
    # Now, based on `type_name` and `id`
    # find an object in your application 
    # This will give the user access to all records in your db
    # so you might want to restrict this properly
    Object.const_get(type_name).find(object_id)
  }
end

此外,您的所有类型都应实现 ruby gem 提供的 NodeInterface,并公开 global_id_field 而不是 ID 类型:

PostType = GraphQL::ObjectType.define do
  name "Post"
  # Implements the "Node" interface for Relay
  interfaces [GraphQL::Relay::Node.interface]
  # exposes the  global id
  global_id_field :id
  field :name, types.String
end

这将允许中继像这样重新获取数据:

query {
  node(id: "RmFjdGlvbjox") {
    id
    ... on Post {
      name
    }
  }
}

Relay 还使用了一个 babel-relay-plugin,它需要生成一个 schema.json 并可供客户端使用,如果你正在构建一个没有视图渲染的孤立 API,那么要走的是让客户端获取架构而不是在服务器中执行该工作,例如 apollo-codegen 可以工作。但是,如果您正在构建一个 rails 应用程序并需要同一应用程序中的模式,那么您可以 运行 一个内省查询并使用 rake 任务将结果保存到一个 json 文件:

Schema.execute GraphQL::Introspection::INTROSPECTION_QUERY

最后,你需要了解 Relay 表示一对多的连接关系:

PostType = GraphQL::ObjectType.define do
  # default connection
  # obj.comments by default
  connection :comments, CommentType.connection_type

  # custom connection
  connection :featured_comments, CommentType.connection_type do
    resolve ->(post, args, ctx) {
      comments = post.comments.featured

      if args[:since]
        comments = comments.where("created_at >= ?", since)
      end

      comments
    }
  end
end

连接支持一些开箱即用的参数,您可以在连接查询中使用 firstlastbeforeafter

query {
  posts(first: 5) {
    edges {
      node {
        name
      }
    }
  }
}

所有这些都记录在 Relay documentation so make sure you read it as well as the graphql-ruby 文档中。