GraphQL的推荐

这篇文章是SmartDrive Advent Calendar 2017的第四天的文章。
大家好,我是在SmartDrive担任后端工程师的@ryota-koganezawa。接下来我将会谈谈关于我们即将发布的产品中使用的GraphQL(ruby)和各种插件。
同时,我会尽量简洁地介绍,如果你想了解更多细节,请参考其他文章。

我主要希望谈论以下内容。

    • GraphQLとは?

 

    • GraphQLを採用した理由

 

    • GraphQL-rubyのCacheにおけるTips

 

    • GraphQL-rubyのN+1対応

 

    • GraphQLのAPIドキュメント

 

    • インターフェイス

 

    • 感想

 

    おわりに

GraphQL是什么?

    • 2012年にFacebookが開発、2015年7月にRFCドラフト案を公開

 

    • クライアント・サーバアプリケーション向けのデータモデリング記述のためのクエリ言語

 

    詳細はこちらをご覧ください。

选择使用GraphQL的原因

很常有提到的引入GraphQL的好处。

    • 階層構造を備えたクエリ構造

 

    • ビュー要求の記述しやすさ

 

    強力な型システム…etc

我认为还有其他的原因,而不仅仅是等待。

首先,就我目前的情况来说…

    • 新規サービス開発において、モデリングだけがFixした

 

    • フロント実装(デザイン含め)がなかなか定まらない。且つ変更される可能性大

ステークホルダーが多く、仕様が局所的にFixされていく。
つまり、バックエンド側は柔軟に設計し、それなりの変更要求に耐えられる実装にしなくてはならない

在谈到灵活的设计时,提高抽象度并遵循单一责任原则…反转依赖原则…接口隔离原则…等等等等各种实践,我认为都有一定的存在。但是,在『建模已经相对固定』的情况下,我没有想到适合推进后端开发的设计模式。或者,可以为所有资源准备符合RESTful API的端点…

在这个时候,Graphql是我们命中注定的相遇。我们提供了适用于层次结构化模型集合的终端,让您自由使用,无需担心这边的任务,可以专注于其他任务、项目和团队构建。虽然只是后端,实际上引入的成本(包括学习成本)只需1至2天。另外,因为在同一终端(同一方法)接收query和mutation让我有些犹豫,所以我们这次只采用了query。

GraphQL-ruby缓存的技巧

关于缓存相关的内容,我们参考了GitHub员工Marc-André的文章。
由于解析查询(query)需要一些成本(取决于查询的大小),所以这里提到了应该将其缓存起来。
我们在参考的文章中稍微修改了一下代码,以下是示例代码。

variables = ensure_hash(params[:variables]
result = Schema.execute(document: document, variables: variables)

# Caching GraphQL queries with GraphQL-ruby and Rails.
# @see: github staff(Marc-André) http://mgiroux.me/2016/graphql-query-caching-with-rails/
def document
  ::Rails.cache.fetch(cache_key, expires_in: EXPIRES_IN) do
    GraphQL.parse(params[:query])
  end
end

# Handle form data, JSON body, or a blank value.
def ensure_hash(ambiguous_param)
  case ambiguous_param
  when String
    if ambiguous_param.present?
      ensure_hash(JSON.parse(ambiguous_param))
    else
      {}
    end
  when Hash, ActionController::Parameters
    ambiguous_param
  when nil
    {}
  else
    raise ArgumentError, "Unexpected parameter: #{ambiguous_param}"
  end
end

GraphQL-ruby的N+1解决方案

在引入GraphQL时可能会有一个担忧,即N+1问题。
作为解决方法,我们引入了graphql-batch。

在README.md中只列出了一个加载器,但实际上有两种模式可供选择,并且都可以进行自定义。以下是这两种模式的示例。

初期化時にモデルを渡し、perform時にWhere句の条件を渡すパターン

record loader

初期化時にモデルを渡し、perform時にassociationを渡すパターン

association loader

GraphQL的API文档

作为API文档,我认为GraphiQL是唯一选择。它既可用于调试,还可以作为API文档服务器,非常出色。有时也被称为GraphiQL IDE。

graphiql.png

按照README.md中的指示挂载GraphiQL,访问http://localhost:8080/graphiql,将显示用于调试执行查询的API控制台。
就模式定义而言,似乎在启动API控制台时从app/graphql/types目录下加载了各种类型,并显示了字段信息等。
只需将此URL告知前端开发人员,就可以参考模式定义并进行调试开发。

界面 (jiè

在Ruby on Rails中,有一种更加DRY(Don’t Repeat Yourself)的编写方式,即通过使用接口(GraphQL::InterfaceType)来实现。通过定义一个接口并通过GraphQL::ObjectType继承该接口,就不再需要重复定义相同的字段了。

实施样本

::Types::ActiveRecordInterface = GraphQL::InterfaceType.define do
  name 'ActiveRecordInterface'
  description 'ActiveRecordInterface'

  field :id, !types.Int
  field :updated_at, !types.String
  field :created_at, !types.String
end
::Types::HogeType = GraphQL::ObjectType.define do
  interfaces [::Types::ActiveRecordInterface] # ここで共通フィールドとして読み込む

  name 'Hoge'
  description 'Hoge'

  field :code, !types.String
  field :name, !types.String
end

对于GraphQL::InterfaceType,我认为这篇文章非常有参考价值。

触动

由于学习成本低且有丰富的插件等可供选择,因此实际的导入并不困难。由于即将开始前端开发,我们希望团队能够在总结前端技巧的同时评估GraphQL的可行性。

最后

SmartDrive正在积极开展后端工程师的招聘活动。
此外,我们也正在大力招募其他各类工程师。如果您感兴趣,请务必申请!

广告
将在 10 秒后关闭
bannerAds