| /検索を開始 | ctrl + p前の検索項目 | ↑前の検索項目 |
| escフォーカスを解除 | ctrl + n次の検索項目 | ↓次の検索項目 |
| cmd + fページ内検索 (ブラウザ標準) | ?ヘルプの表示 |
このガイドの内容:
従来、Railsの「API」というと、プログラムからアクセスできるAPIをWebアプリケーションに追加することを指すのが通例でした。たとえば、GitHubが提供するAPIはカスタムクライアントから利用できます。
近年、さまざまなクライアント側フレームワークが登場したことによって、Railsで構築したバックエンドサーバーを他のWebアプリケーションとネイティブアプリケーションの間で共有する手法が増えてきました。
たとえば、X.comは自社のWebアプリケーションでパブリックAPIを利用しています。このWebアプリケーションは、JSONリソースを消費するだけの静的サイトとして構築されています。
多くの開発者が、Railsで生成したHTMLフォームやリンクをサーバー間のやりとりに使うのではなく、Webアプリケーションを単なるAPIクライアントにとどめて、JSON APIを利用するHTMLとJavaScriptの提供に専念するようになってきました。
本ガイドでは、JSONリソースをAPIクライアントに提供するRailsアプリケーションの構築方法を解説します。クライアント側フレームワークについても言及します。
RailsでJSON APIを構築することについて、多くの開発者から受ける質問の筆頭は「RailsでJSONを出力するのは大げさすぎませんか?Sinatraじゃダメなんですか?」です。
単なるAPIサーバーであれば、それでもよいでしょう。しかし、フロントHTMLの比重が非常に大きいアプリケーションであっても、アプリケーションロジックのほとんどはビューレイヤ以外の部分にあるものです。
Railsが多くの開発者に採用されている理由は、細かな設定をいちいち決めなくても、すばやくアプリケーションを立ち上げられるからこそです。
APIアプリケーションの開発にすぐ役立つRailsの機能をいくつかご紹介します。
ミドルウェア層で提供される機能
paramsでアクセスできます。もちろん、ネストしたURLエンコードパラメータも扱えます。ETagやLast-Modifiedを使った条件付きGETを扱えます。条件付きGETはリクエストヘッダを処理し、正しいレスポンスヘッダとステータスコードを返します。コントローラにstale?チェックを追加するだけで、HTTPの細かなやりとりはRailsが代行してくれます。HEADリクエストを透過的にGETリクエストに変換し、ヘッダだけを返します。これによって、すべてのRails APIでHEADリクエストを確実に利用できます。Rackミドルウェアのこうした既存の機能を自前で構築する方法も考えられますが、Railsのデフォルトのミドルウェアを「JSON生成専用」に使うだけでも多数のメリットが得られます。
Action Pack層で提供される機能
head :no_contentやredirect_to user_url(current_user)などをすぐ利用できるので、ヘッダレスポンスを自分で書かずに済みます。もちろん、Railsの起動プロセスでは、登録済みのコンポーネントをすべて読み込んで連携します。たとえば、起動中にconfig/database.ymlファイルを使ってActive Recordを設定します。
要約: ビュー層を取り除いたRailsでは、どんな機能を引き続き利用できるのでしょう。手短に言うと「ほとんどの機能」です。
APIサーバーにするRailsアプリケーションをすぐにでも構築したいのであれば、機能を限定したRailsサブセットを作って、必要な機能を順次追加するのがよいでしょう。
API専用Railsアプリケーションの生成には次のコマンドを使います。
$rails new my_api--api
上のコマンドを実行すると、以下の3つが行われます。
ApplicationControllerが通常のActionController::BaseではなくActionController::APIを継承します。ミドルウェアと同様、Action Controllerモジュールのうち、ブラウザ向けアプリケーションでしか使われないモジュールをすべて除外します。新しく作成したAPIで新しいリソースを生成する方法を確認するために、新しいGroupリソースを作成してみましょう。各グループごとに名前を付けます。
$bin/rails g scaffold Group name:stringscaffoldで生成したコードを使えるようにするには、データベーススキーマを更新する必要があります。
$bin/rails db:migrateここでGroupsControllerを開いてみると、API RailsアプリではJSONデータのみをレンダリングしていることがわかります。indexアクションではGroup.allをクエリしてインスタンス変数@groupsに代入しています。これを、renderに:jsonオプションを指定して渡すと、自動的にグループをJSONとしてレンダリングします。
# app/controllers/groups_controller.rbclassGroupsController<ApplicationControllerbefore_action:set_group,only:%i[ show update destroy ]# GET /groupsdefindex@groups=Group.allrenderjson:@groupsend# GET /groups/1defshowrenderjson:@groupend# POST /groupsdefcreate@group=Group.new(group_params)if@group.saverenderjson:@group,status: :created,location:@groupelserenderjson:@group.errors,status: :unprocessable_entityendend# PATCH/PUT /groups/1defupdateif@group.update(group_params)renderjson:@groupelserenderjson:@group.errors,status: :unprocessable_entityendend# DELETE /groups/1defdestroy@group.destroyendprivate# Use callbacks to share common setup or constraints between actions.defset_group@group=Group.find(params[:id])end# Only allow a list of trusted parameters through.defgroup_paramsparams.expect(group:[:name])endend
最後に、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": ...}]既存のアプリケーションをAPI専用に変えるには、以下の手順をお読みください。
config/application.rbのApplicationクラス定義の冒頭に以下の設定を追加します。
config.api_only=true
developmentモードでのエラー発生時に使われるレスポンス形式を設定するには、config/environments/development.rbファイルでconfig.debug_exception_response_formatを設定します。
値を:defaultにすると、デバッグ情報をHTMLページに表示します。
config.debug_exception_response_format=:default
値を:apiにすると、レスポンス形式を変更せずにデバッグ情報を表示します。
config.debug_exception_response_format=:api
config.api_onlyをtrueに設定すると、config.debug_exception_response_formatがデフォルトで:apiに設定されます。
最後に、app/controllers/application_controller.rbの以下のコードを置き換えます。
classApplicationController<ActionController::Baseend
上を以下に変更します。
classApplicationController<ActionController::APIend
APIアプリケーションでは、デフォルトで以下のミドルウェアを利用できます。
ActionDispatch::HostAuthorizationRack::SendfileActionDispatch::StaticActionDispatch::ExecutorActionDispatch::ServerTimingActiveSupport::Cache::Strategy::LocalCache::MiddlewareRack::RuntimeActionDispatch::RequestIdActionDispatch::RemoteIpRails::Rack::LoggerActionDispatch::ShowExceptionsActionDispatch::DebugExceptionsActionDispatch::ActionableExceptionsActionDispatch::ReloaderActionDispatch::CallbacksActiveRecord::Migration::CheckPendingRack::HeadRack::ConditionalGetRack::ETag詳しくは、Rackガイドの「Rails と Rack - ミドルウェアスタックの内容」を参照してください。
ミドルウェアは、Active Recordなど他のプラグインによって追加されることもあります。一般に、ミドルウェアは構築するアプリケーションの種類を問いませんが、API専用Railsアプリケーションでも意味があります。
アプリケーションの全ミドルウェアを表示するには次のコマンドを使います。
$bin/rails middlewareRack::Cacheは、Railsで利用する場合はRailsのキャッシュストアをエンティティストアとメタストアに使います。つまり、たとえばRailsアプリでmemcacheを使うと、組み込みのHTTPキャッシュがmemcacheを使うようになります。
Rack::Cacheを利用するには、最初にrack-cache gemをGemfileに追加し、config.action_dispatch.rack_cacheにtrueを設定する必要があります。この機能を有効にするには、コントローラでstale?を使う必要があります。以下は、stale?の利用例です。
defshow@post=Post.find(params[:id])ifstale?(last_modified:@post.updated_at)renderjson:@postendend
stale?呼び出しは、リクエストにあるIf-Modified-Sinceヘッダと@post.updated_atを比較します。ヘッダが最終更新時より新しい場合、「304 Not Modified」を返すか、レスポンスをレンダリングしてLast-Modifiedヘッダをそこに表示します。
通常、この動作はクライアントごとに行われますが、Rack::Cacheがあるとクライアント間でこのキャッシュを共有できるようになります。以下のように、stale?の呼び出しを使ってクロスクライアントキャッシュを有効にできます。
defshow@post=Post.find(params[:id])ifstale?(last_modified:@post.updated_at,public:true)renderjson:@postendend
Rack::Cacheは上のコードによって、URLに対応するLast-Modified値をRailsキャッシュに保存し、以後同じURLへのリクエストを受信したときにIf-Modified-Sinceヘッダを追加するようになります。
これは、HTTPセマンティクスを利用したページキャッシュと考えることができます。
Railsコントローラ内部でsend_fileメソッドを実行すると、X-Sendfileヘッダが設定されます。実際のファイル送信を担当するのはRack::Sendfileです。
ファイル送信アクセラレーションをサポートするフロントエンドサーバーでは、Rack::Sendfileの代わりにフロントエンドサーバーがファイルを送信します。これにより、Railsはリクエスト処理を早期に完了してリソースを解放できるようになります。
フロントエンドサーバーでのファイル送信に使うヘッダ名は、該当する環境設定ファイルのconfig.action_dispatch.x_sendfile_headerで設定できます。
主要なフロントエンドでRack::Sendfileを使う方法について詳しくは、Rack::Sendfileドキュメントを参照してください。
主要なサーバーでファイル送信アクセラレーションを有効にするには、ヘッダに次のような値を設定します。
# Apacheやlighttpdconfig.action_dispatch.x_sendfile_header="X-Sendfile"# Nginxconfig.action_dispatch.x_sendfile_header="X-Accel-Redirect"
これらのオプションを有効にするには、Rack::Sendfileドキュメントに従ってサーバーを設定してください。
ActionDispatch::Request#paramsは、クライアントからのパラメータをJSON形式で受け取り、コントローラ内部のparamsでアクセスできるようにします。
この機能を使うには、JSONエンコード化したパラメータをクライアントから送信し、Content-Typeにapplication/jsonを指定する必要があります。
以下はサンプルコードです。
fetch('/people',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({person:{firstName:'Yehuda',lastName:'Katz'}})}).then(response=>response.json())
ActionDispatch::RequestはこのContent-Typeを認識し、パラメータは以下のようになります。
{person:{firstName:"Yehuda",lastName:"Katz"}}
通常は以下のセッション管理用ミドルウェアは不要なので、APIから除外されています。ブラウザもAPIクライアントとして使われる場合は、以下のいずれかを追加するとよいでしょう。
ActionDispatch::Session::CacheStoreActionDispatch::Session::CookieStoreActionDispatch::Session::MemCacheStoreここで注意が必要なのは、これらのミドルウェア(およびセッションキー)はデフォルトではsession_optionsに渡されることです。つまり、通常どおりにsession_store.rbイニシャライザを追加してuse ActionDispatch::Session::CookieStoreを指定しただけではセッションは機能しません(補足: セッションは動作しますがセッションオプションが無視されるので、セッションキーがデフォルトで_session_idになります)。
そのため、セッション関連のオプションはイニシャライザで設定するのではなく、以下のように自分が使うミドルウェアが構築されるより前の場所(config/application.rbなど)に配置して、使いたいオプションをミドルウェアに渡さなければなりません。
# 以下のsession_optionsも利用可能config.session_store:cookie_store,key:"_your_app_session"# このミドルウェアはすべてのセッション管理で必須(session_storeに関わらず)config.middleware.useActionDispatch::Cookiesconfig.middleware.useconfig.session_store,config.session_options
Railsではこの他にも、APIアプリケーション向けのミドルウェアを多数利用できます。特に、ブラウザもAPIクライアントとして使う場合は以下のミドルウェアが便利です。
Rack::MethodOverrideActionDispatch::CookiesActionDispatch::Flashこれらのミドルウェアは、以下の方法で追加できます。
config.middleware.useRack::MethodOverride
API専用ミドルウェアに含めたくないミドルウェアは、以下の方法で削除できます。
config.middleware.delete::Rack::Sendfile
これらのミドルウェアを削除すると、Action Controllerの一部の機能が利用できなくなりますので、ご注意ください。
APIアプリケーション(ActionController::APIを利用)には、デフォルトで次のコントローラモジュールが含まれます。
ActionController::UrlFor:url_forなどのヘルパーを提供ActionController::Redirecting:redirect_toをサポートAbstractController::RenderingとActionController::ApiRendering: 基本的なレンダリングのサポートActionController::Renderers::All:render :jsonなどのサポートActionController::ConditionalGet:stale?のサポートActionController::BasicImplicitRender: 指定がない限り空のレスポンスを返すActionController::StrongParameters: パラメータのフィルタリングをサポート(Active Modelのマスアサインメントと連携)ActionController::DataStreaming:send_fileやsend_dataのサポートAbstractController::Callbacks:before_actionなどのヘルパーをサポートActionController::Rescue:rescue_fromをサポートActionController::Instrumentation: Action Controllerで定義するinstrumentationフックをサポート(詳しくはinstrumentationガイドを参照)ActionController::ParamsWrapper: パラメータハッシュをラップしてネステッドハッシュにする(たとえばPOSTリクエスト送信時のroot要素が必須でなくなる)ActionController::Head: コンテンツのないヘッダのみのレスポンスを返すのに用いる他のプラグインによってモジュールが追加されることもあります。ActionController::APIの全モジュールのリストは以下のコマンドで表示できます。
irb> ActionController::API.ancestors - ActionController::Metal.ancestors=> [ActionController::API, ActiveRecord::Railties::ControllerRuntime, ActionDispatch::Routing::RouteSet::MountedHelpers, ActionController::ParamsWrapper, ... , AbstractController::Rendering, ActionView::ViewPaths]
Action Controllerのどのモジュールも、自身が依存するモジュールを認識しているので、コントローラにモジュールを含めるだけで、必要な依存モジュールも同様に設定できます。
よく追加されるのは、次のようなモジュールです。
AbstractController::Translation: ローカライズ用のlメソッドや翻訳用のtメソッドActionController::HttpAuthentication::Basic::ControllerMethodsActionController::HttpAuthentication::Digest::ControllerMethodsActionController::HttpAuthentication::Token::ControllerMethodsActionView::Layouts: レンダリングでレイアウトをサポートActionController::MimeResponds:respond_toをサポートActionController::Cookies:cookiesのサポート(署名や暗号化も含む)。cookiesミドルウェアが必要。ActionController::Caching: APIコントローラでビューのキャッシュをサポート(ただし以下のようにコントローラ内でキャッシュストアを手動で指定する必要がある)
classApplicationController<ActionController::APIinclude::ActionController::Cachingself.cache_store=:mem_cache_storeend
Railsはこの設定を「自動的には渡しません」。
モジュールはApplicationControllerに追加するのが最適ですが、個別のコントローラに追加することも可能です。
Railsガイドは GitHub のyasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽にPull Request を出して頂けると嬉しいです。Pull Request の送り方についてはGitHub の README をご参照ください。
原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひRails コミュニティに貢献してみてください 🛠💨✨
本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。
Railsガイド運営チーム (@RailsGuidesJP)

Railsガイドは下記の協賛企業から継続的な支援を受けています。もしご興味あれば、協賛プランから気軽にお問い合わせいただけると嬉しいです。