APIエンドポイントの作成

はじめに

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 Guides
Active 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操作でそのエンドポイントにリクエストを実行することができるものです。
複数人で開発したりするときには採用される場合があるので知識として知っておくとよいです。

コメント

タイトルとURLをコピーしました