はじめに
Railsのサーバーにapiのエンドポイントを作成します。
要はフロントエンドアプリケーションはDBに直接アクセスすることができないので、リソース(例えばDBの中身)が欲しいときにはRailsに対してGETリクエストを送信してその返ってきた値を使って画面を作成します。
Rails側でGETリクエストを受け取る窓口と受け取った後の処理を実装していきます。
ゴールの確認
Railsがリクエストを受け取るためのapiエンドポイントを作成
postmanを使って実際にリクエストを送信できる
active_model_serializerを導入してレスポンスの中身をカスタマイズする
ここでの差分はgithubにあげています。困った際は参考にしてみてください
routeの設定
まずはroutingの設定です。
localhost:3000/api/v1/userに対するGETリクエストを受け取れるようにします
おそらくこのアプリケーション全体としてはrouteの数は果てしないくらい肥大化する予定はありませんが、商用のアプリケーションを作成しているとパスを作成していくだけでもroute.rbのファイルはどんどん肥大化していくと思います。
その際にrailsが最初から用意しているroute.rbに全てのパスを書き込んでしまうとメンテナンスが大変になってしまいます。
そこで、railsにはrouteをファイル分割するための技が用意されています。apiに関するものはroute.rbに直接記載するのではなく、別のファイルにおいて、それをroute.rbで読みこむような形にします。
まずはapiのためのroutingを書くファイルを用意します。config配下にroutesディレクトリを作成してください。その下にapi.rbファイルを作成します
namespace :api do
namespace :v1 do
resource :user, only: %i[show]
end
end
次にroutes.rbに先ほど作成したファイル名を読み込みます
# frozen_string_literal: true
Rails.application.routes.draw do
draw(:api) # ここを追記
resource :user, only: %i[show update create]
end
ここまでできたら上手く読み込めているか確認しましょう。
rails routes
を実行して、apiのパスが作成されていることを確認してください。
このコマンドを実行すると、全てのパスが表示されます。最初からrailsは多くのパスが用意されていますし、実装が進むと全てのパスを見るのが辛くなります。ある程度文字で絞るとよいです。
rails routes | grep api
とすることでapiの文字を含むもののみに限定されるので、効率がいいです
api_v1_user GET /api/v1/user(.:format) api/v1/users#show
このようなパスが追加されていることが確認できていれば成功です
パス名について
api/v1/**
となるようにパス名を設定しました。
v1はversion1の意味です。
apiのバージョン管理のためにv1をパスに入れています。これはapiを作成するときによく使われるものです。
apiをいろんなアプリケーションに展開していて、既存のapiをアップデートしてレスポンスや必要なパラメータが変化したときにapiの仕様が急に変わってしまうとそのapiを使って動作しているアプリケーション全体に大きな影響を及ぼしてしまいます。そのため、apiのアップデートが行われるときはバージョンで分割して古いバージョンのものを残すことでアップデートのインパクトを抑えることに用いられます。
controllerの作成
コントローラを作成します。
以前作成したコントローラの親クラスはrailsがデフォルトで用意してくれていたApplicationControllerが用いられていました。(backend/app/controllers/users_controller.rb参照)
このApplicationControllerはActionController::Baseを親クラスにもっています。
ActionController::Baseはアクションに到達したときにテンプレートを返したり、csrfトークンを検査したりrailsのテンプレートとのやりとりをするための機能が含まれています。
このApplicationControllerを新しくapi用に作成するコントローラの親クラスにしてしまうと、apiでは不要な機能がたくさん付いてきてしまって上手く実装できないため、ActionController::APIを親クラスに持つApiControllerを新規に作成し、api系のコントローラはこれを親クラスに設定します。
ApiControllerの作成
class ApiController < ActionController::API
end
Api用のUsersControllerの作成
class Api::V1::UsersController < ApiController
def show
p "yeah! your on the api user show action!"
end
end
動作確認
では動作確認をしていきましょう
もっとも簡単な動作確認の方法はcurlコマンドを使う方法です。
curlコマンドはターミナルからapiを実行するものです。
curl http://localhost:3000/api/v1/user
これを実行したとき、rails側のログに
Started GET "/api/v1/user" for
...
"yeah! your on the api user show action!"
...
Completed 204 No Content in 2ms (ActiveRecord: 0.0ms | Allocations: 125)
のような形で出ていれば成功です。
この先もターミナルからcurlコマンドを叩いてもよいのですが、いろんなapiを毎回コマンド入力していくのは大変ですし、postやputのようにリクエストの中にbodyを入れたり、headerを入れたりしようとするとコマンドがどんどん長くなって大変です。
そんなときに便利なのがpostmanです。
GUIからリクエストの内容を入力していき、その設定を保存して使いまわしたりすることができます。
実際の画面はこんな感じです
リクエストメソッドとパスを指定して、headerやbodyを入れてSendをすると、下にその結果が出力されます。
localhost向けへはdesktopアプリケーションで起動しないと送信できない仕様になっているのでデスクトップアプリケーションを入れる必要があります。
この先もapiの動作確認にはpostmanを利用する予定です
レスポンス
それでは少しコントローラの中身を実装してuser情報を返してみましょう
class Api::V1::UsersController < ApiController
def show
render json: user
end
private
def user
@user ||= User.first
end
end
これでもう一度リクエストを実行すると、
{
"id": 1,
"name": "John Smith",
"email": "example@mail.com",
"postal_code": "1111111",
"address": "1234 Main St",
"created_at": "2024-06-11T07:40:16.205Z",
"updated_at": "2024-06-11T07:40:16.205Z"
}
のような結果が得られます。
このままでも問題はなさそうですが、idやcreated_at、updated_atはフロントエンドに渡す必要がないので送らないようにしたいです。
その際に
render json: {name: user.name, email: user.email, postal_code: user.postal_code, address: user.address}
と長々と記載しても実現はできるのですが、レスポンス用の処理が複雑化したときにすぐに限界がきてしまいます。
そこで、レスポンスする内容を簡単にカスタマイズするためにactive_model_serializerを導入します。
active_model_serializerの導入
それではgemのインストールをしていきましょう
devやtest、本番環境関係なく全ての環境で必要なライブラリなので直下におきます
...
# gem "sassc-rails"
# Use Active Storage variants
Active Storage Overview — Ruby on Rails GuidesActive Storage OverviewThis guide covers how to attach files to your Active Record models.After reading this guide, you ...
# gem "image_processing", "~> 1.2"
gem 'bootstrap', '~> 5.2.2'
gem 'active_model_serializers'
...
bundle install し、rails restart をしておきましょう
まずはserizaliserを置くためのディレクトリを用意します。app/serializersを作成してください。
次に全てのserializerに共通して利用する親クラスのApplicationSerializerを作成します
class ApplicationSerializer < ActiveModel::Serializer
end
userの中身をカスタムするためのserializerを作成します
class UserSerializer < ApplicationSerializer
attributes :name
attributes :email
attributes :postal_code
attributes :address
end
最後にusers controllerでこのシリアライザーを利用します
class Api::V1::UsersController < ApiController
def show
render json: user, serializer: UserSerializer
end
private
def user
@user ||= User.first
end
end
これでもう一度動作確認をしてみましょう。
レスポンスの結果が変わることを確認してください
{
"name": "John Smith",
"email": "example@mail.com",
"postal_code": "1111111",
"address": "1234 Main St"
}
今回はserializerの最もシンプルな実装方法になりました。キー名を変えたり、元々のオブジェクトの値から一定の処理をした後の結果をレスポンスしたり、リレーションがある場合にはそのリレーション先のレコードもレスポンスに載せるなどなど様々な機能があります。
おわりに
Railsの最初のAPIを実装していきました。
一つ目のAPIなので新しく作成することが多いですが、次回以降はこの作成したものを元に作成していけるので、よりアプリケーション独自の実装に時間が割けるようになっていきます。
apiの動作確認のためにpostmanとcurlを紹介しました。
特にcurlはlinuxの環境であれば基本的に動作するコマンドなので、インフラの構築のときにも用いたりします。どの動作確認の方法も覚えておくと便利です。
また、ここでは紹介できていませんが、apiのドキュメント管理兼動作確認の方法としてswaggerを用いることもあります。
どんなapiのエンドポイントが用意されていて、それがどんなパラメータを要求し、どんな結果を返すのかなど、とても見やすいドキュメントをyml形式で簡単に書くことができ、そのドキュメントからGUI操作でそのエンドポイントにリクエストを実行することができるものです。
複数人で開発したりするときには採用される場合があるので知識として知っておくとよいです。
コメント