在 Rails 项目里使用 Graphql

简介: 在 Rails 项目里使用 Graphql

Rails 一直走在技术的前沿,从最早引入 scss、coffee 等就可以说明,Rails 一直在努力引入前端的前沿的技术。

过去的一年,前端涌现出各种框架,而 Rails 社区紧随其后有了相应的解决方案,比如 react-rails、react_on_rails 等等。

本文主要介绍了一下如何在 Rails 项目中使用 GraphQL,并抛出一些关于用 GraphQL 取代 API 的一些最佳实践,未必正确,权当抛砖引玉。欢迎拍砖。

关于GraphQL的介绍大家可以参看这里。这里主要介绍怎么集成到 Rails 项目中。

我们先创建一个 Rails 项目

$ rails new MyBlogApp
.
.
.
$ cd MyBlogApp

创建 Rails GraphQL API

首先,我们把rack-cors gem 添加到 Gemfile 中。

gem 'rack-cors', :require => 'rack/cors'

然后把以下内容添加至config/application.rb:

# config/application.rb
module MyBlogApp
  class Application < Rails::Application
    # ...
    config.middleware.insert_before 0, "Rack::Cors" do
      allow do
        origins '*'
        resource '*', :headers => :any, :methods => [:get, :post, :options]
      end
    end
  end
end

注意:在生产环境这样配置是相当危险的,具体配置请参考官方文档

然后我们生成一个 Blog model

$ rails generate model Blog title:string content:string author_id:integer

然后再添加一个 Author 的 model

rails generate model Author name:string

Blog 属于 Author:

# app/models/blog.rb
class Blog < ActiveRecord::Base
  belongs_to :author
end

Author 有许多 Blogs

# app/models/author.rb
class Author < ApplicationRecord
  has_many :blogs
end

然后,运行:

$ rails db:migrate

到这里为止,我们的 App 的基本内容已经告一段落了。 接下来,我们就开始创建 GraphQL API。

首先,在 Gemfile 里添加GraphQL gem:

gem 'GraphQL'

然后运行$ bundle install, 安装 gem。

我们创建 GraphQL API 的步骤是:

  1. 先创建 Type
  2. 再创建 Schema
  3. 创建 query

首先,我们在app目录下创建graph目录:

$ mkdir -p app/graph
$ mkdir -p app/graph/types

然后在config/application.rb文件里添加以下路径:

# config.application.rb
config.autoload_paths << Rails.root.join('app', 'graph')
config.autoload_paths << Rails.root.join('app', 'graph', 'types')

让我们先创建一个Query Type:

# app/graph/types/query_type.rb
QueryType = GraphQL::ObjectType.defile do
    name "Query"
    description 'The query root for this schema'
    field :blog do
       type BlogType
       argument :id, !types.ID
       resolve -> (obj, args, context) {
          Blog.find args[:id]
       }
    end
end

作为这次查询的根,我们定义了一个字段 blog,它会根据 id 返回一个 Blog 记录。

然后我们继续定义blog_typeauthor_type

# app/graph/types/blog_type.rb
BlogType = GraphQL::ObjectType.define do
   name 'Blog'
   description 'A Blog'
   field :title, types.String
   field :content, types.String
   field :author do
      type AuthorType
      resolve -> (obj, args, context) {
          obj.author
      }
   end
end
# app/graph/types/author_type.rb
AuthorType = GraphQL::ObjectType.define do
   name 'Author'
   description 'Author of Blogs'
   field :name, types.String
end

然后让我们在创建 GraphQL Schema:

# app/graph/blog_schema.rb
BlogSchema = GraphQL::Schema.define do
  query QueryType
end

现在剩下的就是将我们的 GraphQL Schema 的端点暴露出来,最好使用 POST 的方式: 别忘了修改此处:

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  # Use :null_session here
  protect_from_forgery with: :null_session
end

接下来,我们先生成一个QueriesController:

$ rails generate controller Queries create
# app/controllers/queries_controller.rb
class QueriesController < ApplicationController
  def create
    query_string = params[:query]
    query_variables = params[:variables] || {}
    result = BlogSchema.execute(query_string, variables: query_variables)
    render json: result
  end
end

在config/routes.rb 里添加以下路由:

resources :queries, via: [:post, :options]

That‘s it!

现在我们可以在终端下测试:

$ rails server

打开另一个终端:

$ rails console
> Blog.create title: "Intro to GraphQL", content: "Something something something. Blah blah blah. Etc etc etc."
> exit
$ curl -XPOST -d 'query={ blog(id: 1) { title content }}' http://localhost:3000/queries

返回:

{"data":{"blog":{"title":"Intro to GraphQL","content":"Something something something. Blah blah blah. Etc etc etc."}}}

后记:

几个思考:

  1. 与 ActiveRecord Serialiizer 相比,更灵活
  2. 验证:官方建议验证放在业务逻辑层,因此少量的 REST API 至少目前还是必不可少的。当然不差钱,可以用GraphQL::Pro
  3. 分页:我目前还没有测试,只是根据官方文档理解,无需再引入分页的 gem。因为 GraphQL 有相关的指令来进行分页。
  4. 异常处理:异常可以重写resolve方法,如: 定义个一个RescueFrom类放置到app/classes目录下面:
class RescueFrom
  def initialize error_superclass, resolve_func
    @error_superclass = error_superclass
    @resolve_func = resolve_func
  end
  def call obj, args, ctx
    @resolve_func.call obj, args, ctx
  rescue @error_superclass => err
    puts err.message
  end
end

然后重写blog_type.rb:

BlogType = GraphQL::ObjectType.define do
  name "Blog"
  description "A Blog"
  field :title, types.String
  field :content, types.String
  field :author do
    type AuthorType
    resolve RescueFrom.new(ActiveRecord::RecordNotFound,  -> (obj, args, ctx) {
      obj.author
    })
  end
end

但是,这种解决方法并不优雅,不能像在类似BaseController::ActionController这样的基类里使用rescue_from达到一劳永逸的效果。

总体来说,推荐指数,依然五星,希望大家尝试一下。

相关文章
|
canal 存储 SQL
MySQL 与 Redis 缓存的同步方案
本文介绍MySQL与Redis缓存的同步的两种方案 方案1:通过MySQL自动同步刷新Redis,MySQL触发器+UDF函数实现 方案2:解析MySQL的binlog实现,将数据库中的数据同步到Redis 一、方案1(UDF)
MySQL 与 Redis 缓存的同步方案
|
前端开发
【Sa-Token】7、Sa-Token抛出的异常统一处理
在 Sa-Token 的登录,授权,验证过程中,会抛出很多的异常,我们不能将这些异常信息直接返回给用户,因为用户是看不懂这些异常信息的,我们就需要对这些异常信息进行处理,处理之后再返回展示给前端用户
1913 0
|
Docker 容器
使用阿里云 docker 镜像加速
1.创建docker daemon.json 2.添加docker镜像加速地址 3.重启守护进程
1777 1
|
算法
轨迹系列——一种基于中值滤波的轨迹纠偏方法和几点思考
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 在无路网的情况下,如何进行轨迹纠偏也是一个很多人在研究的内容,各种方案均有很多,有基于不同滤波算法的,也有基于机器学习的,等等。
3114 0
|
Web App开发 JavaScript 前端开发
WebRTC 和 RTC 有什么区别?
【10月更文挑战第25天】WebRTC是RTC的一种具体实现方式,侧重于网页端的实时通信,具有便捷性和跨平台性等特点;而RTC则是一个更广泛的概念,包括了各种不同平台和技术实现的实时通信方式,应用场景更加丰富多样。在实际应用中,需要根据具体的需求和场景选择合适的实时通信技术。
|
10月前
|
数据采集 存储 算法
【C++数据结构——图】图的遍历(头歌教学实验平台习题) 【合集】
本文介绍了图的遍历算法,包括深度优先遍历(DFS)和广度优先遍历(BFS)。深度优先遍历通过递归方式从起始节点深入探索图,适用于寻找路径、拓扑排序等场景;广度优先遍历则按层次逐层访问节点,适合无权图最短路径和网络爬虫等应用。文中提供了C++代码示例,演示了如何实现这两种遍历方法,并附有测试用例及结果,帮助读者理解和实践图的遍历算法。
508 0
|
存储 SQL Prometheus
【TiDB原理与实战详解】1、原理与基础优化~学不会? 不存在的!
TiDB 是一款开源的分布式关系型数据库,具备水平扩展、高可用性和强一致性等特点,适用于高并发、低延迟的大规模数据处理场景。其架构设计灵感源自 Google 的 Spanner 和 F1,并兼容 MySQL。TiDB 集群由 TiDB Server(无状态 SQL 层)、PD(元数据管理模块)和 TiKV Server(分布式存储层)组成,还包含 TiFlash(列存储引擎)以加速分析型查询。TiDB 支持分布式事务和多种事务模式,适用于 OLTP 和 HTAP 场景,如电商平台和金融系统。此外,TiDB 的部署要求包括高性能硬件配置和特定网络设置,以确保系统的稳定性和高效运行。
|
消息中间件 监控 API
深入浅出微服务架构设计原则
在软件开发的宇宙中,微服务如星辰般璀璨,引领着分布式系统的航向。本文将带你穿梭于微服务的星系,探索其背后的设计哲学与实践精髓,从服务边界的划分到数据一致性的保障,再到服务的通信与协作,我们将一同揭开微服务架构高效、可扩展且灵活的秘密。
253 4
|
JSON Android开发 开发者
构建高效Android应用:采用Kotlin协程优化网络请求
【5月更文挑战第31天】 在移动开发领域,尤其是针对Android平台,网络请求的管理和性能优化一直是开发者关注的焦点。随着Kotlin语言的普及,其提供的协程特性为异步编程提供了全新的解决方案。本文将深入探讨如何利用Kotlin协程来优化Android应用中的网络请求,从而提升应用的响应速度和用户体验。我们将通过具体实例分析协程与传统异步处理方式的差异,并展示如何在现有项目中集成协程进行网络请求优化。
|
程序员 开发工具 git
【程序员英语 代码提交】C++工程师的代码提交艺术:git commit 时 精确表达与最佳实践
【程序员英语 代码提交】C++工程师的代码提交艺术:git commit 时 精确表达与最佳实践
400 1