Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Build REST API with GraphQL Ruby

Build REST API with GraphQL Ruby

Avatar for Fumiaki MATSUSHIMA

Fumiaki MATSUSHIMA

August 28, 2020
Tweet

More Decks by Fumiaki MATSUSHIMA

Other Decks in Programming

Transcript

  1. @mtsmfm 松島 史秋 GraphQL Tokyo 主催者 DbD と Ruby と

    GraphQL が好き 主にバックエンドの開発
  2. 伝えたいこと - 宣言とクエリという考え方は、API サーバの実 装をシンプルにする - GraphQL は勝手にそうなる - REST

    API にも応用できるかも - Ruby は実装例として出したけど Ruby 以外も考え方は 同じはず
  3. REST API を作るときの課題 - 似て非なるリソース - GET /articles - [{id:

    1, title: “a”}, {id: 2, title: “b”}, ...] - GET /articles/:id - [{id: 1, title: “a”, thumbnail_url: “example.com”}] - thumbnail_urlという差分をどう表現するか
  4. 差分をどう表現するか 1. 両方とも thumbnail_url を入れる class ArticleEntity < Entity; end

    def as_json {id: @article.id, title: @article.title, thumbnail_url: @article.thumbnail_url} end end get "/articles" do Article.all.map {|a| ArticleEntity.new(a) }.to_json end get "/articles/:id" do ArticleEntity.new(Article.find(params[:id]).to_json end
  5. 差分をどう表現するか 2. /articles/:id だけ thumbnail_url を入れる class ArticleListEntity < ArticleCommonEntity;

    end class ArticleDetailEntity < ArticleCommonEntity; def as_json super.merge(thumbnail_url: @article.thumbnail_url) end end get "/articles" do Article.all.map {|a| ArticleListEntity.new(a) }.to_json end get "/articles/:id" do ArticleDetailEntity.new(Article.find(params[:id]).to_json end
  6. 差分をどう表現するか 2. /articles/:id だけ thumbnail_url を入れる a. 同じところと違うところの表現が苦しくなりがち i. ArticleEntity、ArticleLiteEntity

    を ArticleCommonEntity から継承 or mixin ii. オプションで渡す 別テーブルだと preload の必要性の有無も 変わってくる
  7. GraphQL なら class ArticleType < GraphQL::Schema::Object field :id, ID, null:

    false field :title, String, null: false field :thumbnail_url, String, null: false end class QueryType < Types::BaseObject field :articles, [ArticleType], null: true field :article, ArticleType, null: true do argument :id, ID, required: true end def articles; Article.all; end def article(id:); Article.find(id); end end class AppSchema < GraphQL::Schema query QueryType end post "/graphql" do AppSchema.execute( Params[:query], Params[:variables] ).to_json end
  8. GraphQL なら - 宣言的に Type class を 1 つ書けば OK

    - クエリによって評価されたりされなかったりによ る区別 => 宣言とクエリ - N+1 も Loader がクエリによって評価されたりさ れなかったりすることで、最低限の計算で解消
  9. GraphQL クライアント問題 - 原理的には JSON を HTTP POST して、レス ポンスが

    parse できればなんでもいい - 型の恩恵を受けようとすると、特に native でク ライアントライブラリへのランタイム依存を持た ない codegen の類が (ほぼ) ない - 既存アプリへの導入の課題となり得る - codegen の作りの問題ではある
  10. GraphQL のメトリクスやログ問題 - 既存の仕組みに乗っかれない - パスによる監視 - HTTP method による監視

    - ログ - 最悪クエリを parse しないと分析できないことがあるか も - BigQuery なら JS 動かせるのでなんでもあり - Operation 名つけとけばなんとかなりそうでは あるものの、既存資産の利用が困難
  11. Persisted Query post "/graphql" do AppSchema.execute(params[:query]).to_json end post "/graphql" do

    query = QueryStore.get(params[:query_id]) AppSchema.execute(query).to_json end
  12. Path-based Persisted Query get "/articles" do AppSchema.execute(<<~GQL).to_json query { articles

    { id, title } } GQL end get "/articles/:id" do AppSchema.execute(<<~GQL, {id: params[:id]}).to_json query getArticle($id: ID!) { article(id: $id) { id, title, thumbnail_url } } GQL end
  13. ご清聴ありがとうございました - 宣言とクエリという考え方は、API サーバの実 装をシンプルにする - GraphQL は勝手にそうなる - REST

    API にも応用できるかも - Ruby は実装例として出したけど Ruby 以外も考え方は 同じはず