REST APIからGraphQLへの移行戦略 - 準備作業(ルビー・オン・レールズ)

Sommaire
目次
この記事は前回の記事に続くもので、REST APIからGraphQLへの移行をテーマにしています。
前回の記事では、この移行を行うために実施したアクションプランを概説しました。
この投稿では準備段階をより詳しく見ていきます。まず、簡単なおさらい:
準備作業
- APIのGraphQL版に含まれるコントローラとアクションを一覧化する。
- コントローラのアクションを抽出してオブジェクトに変換する(デザインパターン command)。
- オプション(強く推奨!):テストカバレッジを更新する。
APIのGraphQL版に含まれるコントローラとアクションの一覧
このフェーズでは、あなた自身がAPIの利用者によってどのアクションが使用されているかを一覧化できる唯一の人物です。
方法論としては、全てのコントローラを網羅的に確認する必要があります。
また、この機会にリファクタリングの予定作業やユニットテストの作成などのメモを取ると良いでしょう。これにより、今後のステップに費やす時間をより正確に見積もることができます。
コントローラのアクションを抽出してオブジェクトに変換する
まずはデザインパターン Command(または Service Object)を確認することをお勧めします。
このステップの目的は、各コントローラのアクションをオブジェクトとして抽出することです。この方法を採ることで、いくつかの利点が得られます:
- コードの依存関係を特定できる;
- コントローラの文脈から独立してロジックをより簡単にテストできる;
- コードを複数の場所で再利用できる;
以下の例では、posts_controller.rb の create アクションのロジックを抽出します。
リファクタリング前:
## app/api/v1/posts_controller.rb
module Api
module V1
class PostsController < ::Api::ApplicationController
def create
## Logique métier
## ...
## ...
if post_repository.save(post)
redirect_to post_path(post)
else
render "new"
end
end
def post_repository
@post_repository ||= ::Repositories::Post.new
end
end
end
end
リファクタリング後:
## lib/command/post/create.rb
module Command
module Post
class Create
def self.exec({ attrs, callbacks, repositories })
new(callbacks, repositories).exec(attrs)
end
def exec(attrs)
## Logique métier
## ...
## ...
if @repositories[:post].save(post)
@callbacks[:success].call(post: post)
else
@callbacks[:failure].call(post: post)
end
end
private
def initialize(callbacks, repositories)
@callbacks = callbacks
@repositories = repositories
end
end
end
end
## app/api/v1/posts_controller.rb
module Api
module V1
class PostsController < ::Api::ApplicationController
def create
::Command::Post::Create.exec(
{
attrs: params,
callbacks: {
success: ->(args) {
@post = args[:post]
redirect_to post_path(@post)
},
failure: ->(args) {
@post = args[:post]
render "new"
},
},
repositories: {
post: ::Repositories::Post.new,
}
}
)
end
end
end
end
さらに詳しく知るための参考リンク:
- コマンドパターンとMVCアーキテクチャ
- Thin controllers, Fat models — MVCの基本原則(Ruby on Rails)
- Ruby / Rails サービスオブジェクトのリファクタリング
- レガシーRailsコントローラのリファクタリング
テストカバレッジを更新する
変更やリファクタリングを行う前に、テストを書き、更新することをお勧めします。これにより安心して大きな変更を加えることができます。
ユニットテストの設定について詳述はしませんが、変更に合わせた例を紹介します。
rspec を使用している場合、以下の例は Command オブジェクトのテスト用テンプレートとして利用できます。
require 'rails_helper'
RSpec.describe ::Command::Post::Create do
let (:callbacks) {
{
success: -> (*args) { :success },
failure: -> (*args) { :failure }
}
}
before do
post_repository = double('::Repositories::Post')
allow(post_repository).to receive(:save).with(an_instance_of(::Post)).and_return(true)
@repositories = {
post: post_repository,
}
end
let (:command_post_create) { ::Command::Post::Create }
describe "create" do
context "the record is created" do
let (:attrs) {
{
title: "Test"
}
}
it "calls success callback" do
result = command_post_create.exec(
attrs: attrs,
callbacks: callbacks,
repositories: @repositories
)
expect(result).to eq :success
end
end
end
end
さらに詳しく知るための参考リンク:
結論
この作業を終えると、コントローラのアクションからビジネスロジックを専用のオブジェクトに分離できているはずです。これらのオブジェクトは依存関係が明確に分かれており、適切にテストできるようになります。
これらのオブジェクトはプロジェクト内のどこでも再利用できるため、2つのAPIバージョン間でコードを重複させるのを避けることができます。
これにより、可読性と構造化の面で大きな価値が得られます。
コメント
読み込み中...