edge
詳細はrubyonrails.orgで: もっとRuby on Rails

API専用アプリケーションに対してRailsを使用する方法

このガイドでは、以下の内容を学ぶことができます:

1 APIアプリケーションとは何ですか?

従来、人々がRailsを「API」として使用すると言った場合、Webアプリケーションと並行してプログラムからアクセス可能なAPIを提供することを意味していました。例えば、GitHubはAPIを提供しており、独自のカスタムクライアントから使用することができます。

クライアントサイドのフレームワークの登場により、より多くの開発者がRailsを使用して、Webアプリケーションと他のネイティブアプリケーション間で共有されるバックエンドを構築しています。

例えば、Twitterは公開APIをWebアプリケーションで使用しており、JSONリソースを消費する静的サイトとして構築されています。

Railsを使用して、フォームやリンクを介してサーバーと通信するHTMLを生成する代わりに、多くの開発者がWebアプリケーションを単なるAPIクライアントとして扱い、JSON APIを消費するHTMLとJavaScriptで配信しています。

このガイドでは、APIクライアントにJSONリソースを提供するRailsアプリケーションの構築について説明します。これには、クライアントサイドのフレームワークも含まれます。

2 なぜJSON APIにRailsを使用するのですか?

Railsを使用してJSON APIを構築する際に多くの人々が抱く最初の疑問は、「Railsを使用してJSONを出力するのはオーバーキルではないか?Sinatraのようなものを使用すべきではないか?」というものです。

非常にシンプルなAPIの場合、これは当てはまるかもしれません。しかし、非常にHTML重視のアプリケーションでも、ほとんどのアプリケーションのロジックはビューレイヤーの外に存在します。

Railsを使用する理由は、開発者が多くの些細な決定をする必要なく、迅速に開発を始めることができるデフォルトの設定を提供しているからです。

デフォルトのRailsミドルウェアスタックが提供する価値を示すために、以下にいくつかのRailsが提供する機能を見てみましょう。

ミドルウェアレイヤーで処理されるもの:

  • リロード: Railsアプリケーションは透過的なリロードをサポートしています。アプリケーションが大きくなり、リクエストごとにサーバーを再起動することが不可能になっても、これは機能します。
  • 開発モード: Railsアプリケーションは開発に適したスマートなデフォルトを備えており、本番時のパフォーマンスに影響を与えることなく、開発を快適に行うことができます。
  • テストモード: 開発モードと同様です。
  • ロギング: Railsアプリケーションはすべてのリクエストをログに記録します。開発時のログには、リクエスト環境、データベースクエリ、基本的なパフォーマンス情報などが含まれます。
  • セキュリティ: RailsはIPスーフィング攻撃を検出して防止し、タイミング攻撃に対しては暗号署名を処理することができます。IPスーフィング攻撃やタイミング攻撃が何かわからない?まさにその通りです。
  • パラメータの解析: パラメータをURLエンコードされた文字列ではなくJSONで指定したいですか?問題ありません。RailsはJSONをデコードし、paramsで利用できるようにします。ネストされたURLエンコードされたパラメータを使用したいですか?それも可能です。
  • 条件付きGET: Railsは条件付きのGET (ETagおよびLast-Modified) リクエストヘッダーを処理し、正しいレスポンスヘッダーとステータスコードを返します。コントローラでstale?を使用するだけで、RailsがHTTPの詳細をすべて処理します。
  • HEADリクエスト: RailsはHEADリクエストを透過的にGETリクエストに変換し、ヘッダーのみを返します。これにより、すべてのRails APIでHEADが確実に機能します。

これらは既存のRackミドルウェアを使用して構築することもできますが、このリストは、単なるJSONの生成であっても、デフォルトのRailsミドルウェアスタックが多くの価値を提供していることを示しています。

Action Packレイヤーで処理されるもの:

  • リソースフルなルーティング: RESTfulなJSON APIを構築する場合、Railsのルーターを使用することが望ましいです。HTTPからコントローラへのクリーンで一貫したマッピングにより、APIをHTTPの観点でモデル化する必要がありません。
  • URL生成: ルーティングの裏側にはURL生成があります。HTTPに基づく良いAPIにはURLが含まれます(例: GitHub Gist API)。
  • ヘッダーとリダイレクトレスポンス: head :no_contentredirect_to user_url(current_user)は便利です。もちろん、手動でレスポンスヘッダーを追加することもできますが、なぜそうする必要がありますか?
  • キャッシュ: Railsはページ、アクション、フラグメントのキャッシュを提供します。フラグメントキャッシュは、ネストされたJSONオブジェクトを構築する際に特に役立ちます。
  • ベーシック認証、ダイジェスト認証、トークン認証: RailsはHTTP認証の3種類をサポートしています。
  • インストルメンテーション: Railsには、アクションの処理、ファイルやデータの送信、リダイレクト、データベースクエリなど、さまざまなイベントに対して登録されたハンドラをトリガーするインストルメンテーションAPIがあります。各イベントのペイロードには、関連する情報が含まれます(アクション処理イベントの場合、コントローラ、アクション、パラメータ、リクエストフォーマット、リクエストメソッド、リクエストの完全なパスなど)。
  • ジェネレータ: リソースを生成し、モデル、コントローラ、テストスタブ、ルートを一度のコマンドで作成して、さらに調整することができると便利です。マイグレーションなども同様です。
  • プラグイン: 多くのサードパーティライブラリは、ライブラリとWebフレームワークを設定して結びつけるコストを削減または排除するためのRailsのサポートを提供しています。これには、デフォルトのジェネレータのオーバーライド、Rakeタスクの追加、Railsの選択(ロガーやキャッシュバックエンドなど)の尊重などが含まれます。 もちろん、Railsの起動プロセスは、すべての登録されたコンポーネントを結びつける役割も果たします。 たとえば、Railsの起動プロセスは、Active Recordの設定時にconfig/database.ymlファイルを使用します。

短いバージョンは:ビューレイヤーを削除しても、Railsのどの部分がまだ適用可能かを考えたことがないかもしれませんが、答えはほとんどすべてです。

3 基本的な設定

最初にAPIサーバーとして機能するRailsアプリケーションを構築する場合、より限定されたRailsのサブセットから始めて必要に応じて機能を追加できます。

3.1 新しいアプリケーションの作成

新しいAPI Railsアプリを生成できます:

$ rails new my_api --api

これにより、次の3つの主なことが行われます:

  • 通常よりも制限されたミドルウェアセットでアプリケーションを構成します。具体的には、デフォルトではブラウザアプリケーションに主に有用なミドルウェア(クッキーサポートなど)は含まれません。
  • ApplicationControllerActionController::BaseではなくActionController::APIから継承するように構成します。ミドルウェアと同様に、ブラウザアプリケーションで主に使用される機能を提供するAction Controllerモジュールは除外されます。
  • 新しいリソースを生成するときに、ビュー、ヘルパー、アセットの生成をスキップするようにジェネレータを構成します。

3.2 新しいリソースの生成

新しく作成したAPIがリソースの生成をどのように処理するかを確認するために、新しいGroupリソースを作成してみましょう。各グループには名前があります。

$ bin/rails g scaffold Group name:string

スキャフォールドされたコードを使用する前に、データベーススキーマを更新する必要があります。

$ bin/rails db:migrate

これでGroupsControllerを開くと、API RailsアプリではJSONデータのみをレンダリングしていることに気付くはずです。インデックスアクションでは、Group.allをクエリして@groupsというインスタンス変数に割り当て、:jsonオプションを使用して自動的にグループをJSONとしてレンダリングします。

# app/controllers/groups_controller.rb
class GroupsController < ApplicationController
  before_action :set_group, only: %i[ show update destroy ]

  # GET /groups
  def index
    @groups = Group.all

    render json: @groups
  end

  # GET /groups/1
  def show
    render json: @group
  end

  # POST /groups
  def create
    @group = Group.new(group_params)

    if @group.save
      render json: @group, status: :created, location: @group
    else
      render json: @group.errors, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /groups/1
  def update
    if @group.update(group_params)
      render json: @group
    else
      render json: @group.errors, status: :unprocessable_entity
    end
  end

  # DELETE /groups/1
  def destroy
    @group.destroy
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_group
      @group = Group.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def group_params
      params.require(:group).permit(:name)
    end
end

最後に、Railsコンソールからデータベースにいくつかのグループを追加できます:

irb> Group.create(name: "Rails Founders")
irb> Group.create(name: "Rails Contributors")

アプリにデータがある状態で、サーバーを起動し、http://localhost:3000/groups.jsonを訪れると、JSONデータが表示されます。

[
{"id":1, "name":"Rails Founders", "created_at": ...},
{"id":2, "name":"Rails Contributors", "created_at": ...}
]

4 既存のアプリケーションの変更

既存のアプリケーションをAPIアプリケーションに変更する場合は、以下の手順を読んでください。

config/application.rbで、Applicationクラスの定義の先頭に次の行を追加します。

config.api_only = true

config/environments/development.rbで、config.debug_exception_response_formatを設定して、開発モードでエラーが発生した場合のレスポンスで使用するフォーマットを設定します。

デバッグ情報を含むHTMLページをレンダリングするには、値に:defaultを使用します。

config.debug_exception_response_format = :default

レスポンスフォーマットを保持したままデバッグ情報をレンダリングするには、値に:apiを使用します。

config.debug_exception_response_format = :api

config.debug_exception_response_formatは、config.api_onlyがtrueに設定されている場合にデフォルトで:apiに設定されます。

最後に、app/controllers/application_controller.rbの次のコードを変更します:

class ApplicationController < ActionController::Base
end

次のように変更します:

class ApplicationController < ActionController::API
end

5 ミドルウェアの選択

APIアプリケーションには、デフォルトで次のミドルウェアが含まれています:

  • ActionDispatch::HostAuthorization
  • Rack::Sendfile
  • ActionDispatch::Static
  • ActionDispatch::Executor
  • ActionDispatch::ServerTiming
  • ActiveSupport::Cache::Strategy::LocalCache::Middleware
  • Rack::Runtime
  • ActionDispatch::RequestId
  • ActionDispatch::RemoteIp
  • Rails::Rack::Logger
  • ActionDispatch::ShowExceptions
  • ActionDispatch::DebugExceptions
  • ActionDispatch::ActionableExceptions
  • ActionDispatch::Reloader
  • ActionDispatch::Callbacks
  • ActiveRecord::Migration::CheckPending
  • Rack::Head
  • Rack::ConditionalGet
  • Rack::ETag

詳細については、内部ミドルウェアのセクションを参照してください。

Active Recordを含む他のプラグインは、追加のミドルウェアを追加する場合があります。一般的に、これらのミドルウェアはビルドするアプリケーションのタイプには関係なく、API専用のRailsアプリケーションで意味をなします。 アプリケーション内のすべてのミドルウェアのリストを取得するには、次のコマンドを使用します。

$ bin/rails middleware

5.1 Rack::Cacheの使用

Railsと一緒に使用する場合、Rack::CacheはエンティティとメタストアにRailsキャッシュストアを使用します。つまり、例えばRailsアプリにmemcacheを使用している場合、組み込みのHTTPキャッシュはmemcacheを使用します。

Rack::Cacheを使用するには、まずGemfilerack-cache gemを追加し、config.action_dispatch.rack_cachetrueに設定する必要があります。機能を有効にするために、コントローラでstale?を使用する必要があります。以下にstale?の使用例を示します。

def show
  @post = Post.find(params[:id])

  if stale?(last_modified: @post.updated_at)
    render json: @post
  end
end

stale?の呼び出しは、リクエストのIf-Modified-Sinceヘッダーと@post.updated_atを比較します。ヘッダーが最終更新日より新しい場合、このアクションは「304 Not Modified」レスポンスを返します。それ以外の場合、レスポンスをレンダリングし、Last-Modifiedヘッダーを含めます。

通常、このメカニズムはクライアントごとに使用されます。Rack::Cacheを使用すると、このキャッシュメカニズムをクライアント間で共有できます。stale?の呼び出しでクロスクライアントキャッシュを有効にできます。

def show
  @post = Post.find(params[:id])

  if stale?(last_modified: @post.updated_at, public: true)
    render json: @post
  end
end

これにより、Rack::CacheはURLのLast-Modified値をRailsキャッシュに保存し、同じURLに対する後続の受信リクエストにIf-Modified-Sinceヘッダーを追加します。

HTTPセマンティクスを使用したページキャッシュと考えてください。

5.2 Rack::Sendfileの使用

Railsコントローラ内でsend_fileメソッドを使用すると、X-Sendfileヘッダーが設定されます。Rack::Sendfileは実際のファイル送信を担当します。

フロントエンドサーバが高速ファイル送信をサポートしている場合、Rack::Sendfileは実際のファイル送信作業をフロントエンドサーバにオフロードします。

この目的でフロントエンドサーバが使用するヘッダーの名前をconfig.action_dispatch.x_sendfile_headerを使用して適切な環境の設定ファイルに設定できます。

Rack::Sendfileのドキュメントで、一般的なフロントエンドとのRack::Sendfileの使用方法について詳しく説明しています。

これらのヘッダーの値は、これらのサーバが高速ファイル送信をサポートするように設定された場合に使用できます。

# Apacheとlighttpd
config.action_dispatch.x_sendfile_header = "X-Sendfile"

# Nginx
config.action_dispatch.x_sendfile_header = "X-Accel-Redirect"

Rack::Sendfileのドキュメントの指示に従って、これらのオプションをサポートするようにサーバを設定してください。

5.3 ActionDispatch::Requestの使用

ActionDispatch::Request#paramsは、クライアントからJSON形式のパラメータを受け取り、それをコントローラ内のparamsで利用できるようにします。

これを使用するには、クライアントがJSONエンコードされたパラメータを指定し、Content-Typeapplication/jsonとしてリクエストを行う必要があります。

以下はjQueryの例です。

jQuery.ajax({
  type: 'POST',
  url: '/people',
  dataType: 'json',
  contentType: 'application/json',
  data: JSON.stringify({ person: { firstName: "Yehuda", lastName: "Katz" } }),
  success: function(json) { }
});

ActionDispatch::RequestContent-Typeを認識し、パラメータは次のようになります。

{ person: { firstName: "Yehuda", lastName: "Katz" } }

5.4 セッションミドルウェアの使用

セッション管理に使用される次のミドルウェアは、通常、セッションを必要としないAPIアプリから除外されています。ただし、APIクライアントの1つがブラウザである場合は、これらのいずれかを追加する必要があります。

  • ActionDispatch::Session::CacheStore
  • ActionDispatch::Session::CookieStore
  • ActionDispatch::Session::MemCacheStore

これらを追加するためのトリックは、デフォルトでは追加時にsession_optionsが渡されるため、session_store.rbイニシャライザを追加してuse ActionDispatch::Session::CookieStoreを追加するだけでは通常どおりにセッションが機能しないことです(セッションは機能するかもしれませんが、セッションオプションは無視されます。つまり、セッションキーはデフォルトで_session_idになります)。

イニシャライザの代わりに、ミドルウェアがビルドされる前に(config/application.rbなど)関連するオプションを設定し、次のように好みのミドルウェアに渡す必要があります。

# これは下記のuseのためにsession_optionsを設定します
config.session_store :cookie_store, key: '_interslice_session'

# セッション管理には必須(session_storeに関係なく)
config.middleware.use ActionDispatch::Cookies

config.middleware.use config.session_store, config.session_options

5.5 その他のミドルウェア

Railsには、特にAPIアプリケーションで使用したい他の多くのミドルウェアが付属しています。特にAPIクライアントの1つがブラウザである場合は、これらのミドルウェアのいずれかを使用することができます。

  • Rack::MethodOverride
  • ActionDispatch::Cookies
  • ActionDispatch::Flash

これらのミドルウェアは次のように追加できます。

config.middleware.use Rack::MethodOverride

5.6 ミドルウェアの削除

API専用のミドルウェアセットにデフォルトで含まれている使用しないミドルウェアがある場合は、次のコマンドを使用して削除できます。 ruby config.middleware.delete ::Rack::Sendfile

これらのミドルウェアを削除すると、Action Controllerの特定の機能のサポートも削除されます。

6 コントローラーモジュールの選択

APIアプリケーション(ActionController::APIを使用)は、デフォルトで次のコントローラーモジュールを持っています:

ActionController::UrlFor url_forや同様のヘルパーを利用できるようにします。
ActionController::Redirecting redirect_toのサポート。
AbstractController::RenderingActionController::ApiRendering レンダリングの基本的なサポート。
ActionController::Renderers::All render :jsonや関連するメソッドのサポート。
ActionController::ConditionalGet stale?のサポート。
ActionController::BasicImplicitRender 明示的なレスポンスがない場合に空のレスポンスを返すようにします。
ActionController::StrongParameters Active Modelのマスアサインメントと組み合わせてパラメータのフィルタリングをサポートします。
ActionController::DataStreaming send_filesend_dataのサポート。
AbstractController::Callbacks before_actionや同様のヘルパーのサポート。
ActionController::Rescue rescue_fromのサポート。
ActionController::Instrumentation Action Controllerで定義された計測フックのサポート(詳細は計測ガイドを参照してください)。
ActionController::ParamsWrapper パラメータハッシュをネストされたハッシュにラップし、POSTリクエストを送信する際にルート要素を指定する必要がなくなります。
ActionController::Head コンテンツのないレスポンス(ヘッダーのみ)を返すためのサポート。

他のプラグインは追加のモジュールを追加する場合があります。ActionController::APIに含まれるすべてのモジュールのリストをrailsコンソールで取得できます:

irb> ActionController::API.ancestors - ActionController::Metal.ancestors
=> [ActionController::API,
    ActiveRecord::Railties::ControllerRuntime,
    ActionDispatch::Routing::RouteSet::MountedHelpers,
    ActionController::ParamsWrapper,
    ... ,
    AbstractController::Rendering,
    ActionView::ViewPaths]

6.1 他のモジュールの追加

すべてのAction Controllerモジュールは、依存するモジュールについて知っていますので、コントローラに任意のモジュールを含めることができます。すべての依存関係も含まれ、設定されます。

追加したい一般的なモジュールのいくつか:

  • AbstractController::Translationltのローカライゼーションと翻訳メソッドのサポート。
  • 基本、ダイジェスト、またはトークンのHTTP認証のサポート:
    • ActionController::HttpAuthentication::Basic::ControllerMethods
    • ActionController::HttpAuthentication::Digest::ControllerMethods
    • ActionController::HttpAuthentication::Token::ControllerMethods
  • ActionView::Layouts:レンダリング時のレイアウトのサポート。
  • ActionController::MimeRespondsrespond_toのサポート。
  • ActionController::Cookiescookiesのサポート。署名付きおよび暗号化されたクッキーのサポートも含まれます。これにはクッキーミドルウェアが必要です。
  • ActionController::Caching:APIコントローラのビューキャッシュのサポート。ただし、コントローラ内でキャッシュストアを次のように手動で指定する必要があります:

    class ApplicationController < ActionController::API
      include ::ActionController::Caching
      self.cache_store = :mem_cache_store
    end
    

    Railsはこの設定を自動的に渡しません。

モジュールを追加する最適な場所はApplicationControllerですが、個々のコントローラにもモジュールを追加できます。

フィードバック

このガイドの品質向上にご協力ください。

タイポや事実の誤りを見つけた場合は、ぜひ貢献してください。 開始するには、ドキュメントへの貢献セクションを読んでください。

不完全なコンテンツや最新でない情報も見つかるかもしれません。 メインのドキュメントに不足しているドキュメントを追加してください。 修正済みかどうかは、まずEdge Guidesを確認してください。 スタイルと規約については、Ruby on Rails Guides Guidelinesを確認してください。

修正すべき点を見つけたが、自分で修正できない場合は、 問題を報告してください

そして最後に、Ruby on Railsのドキュメントに関するあらゆる議論は、公式のRuby on Railsフォーラムで大歓迎です。