【API 作成編】Rails API × Meilisearch SDK をつかってみる
こちらの記事の続きです。
これまでの振り返り
前々回、Docker
を用いて、 Rails
× Postgresql
× Meilisearch
の環境を作成しました。
前回は、meilisearch-rails
gem を導入しました。
Postgresql
の users テーブルにテストデータの投入と、上記 gem を用いて Meilisearch
インデックスの構築を行いました。
また、ActiveRecord
メソッドからレコードを操作することで、その変更(レコード作成、更新、削除)が Meilisearch
のインデックスにも同期されることを確認しました。
今回は、検索 API を作成してみて実際どんな取り回しになるのかを試してみたいと思います。
また、ついでに レコード作成、更新、削除 API も作成してみて、users
テーブルと Meilisearch
のインデックスが無事に同期されるのかどうかも確認してみます。
事前準備
コントローラのテンプレート作成とルート設定をします。
コントローラ作成
controller
を作成します。
以下のコマンドを実行して、users_controller
のテンプレートを作成しておきます。
rails g controller api/users/users_controller
ルート設定
ルートの設定も変更しておきます。
API 想定なので、一応 api/
以下で実行できるようにします。
config/routes.rb
Rails.application.routes.draw do
namespace :api do
namespace :users do
get "", to: "users#index"
post "", to: "users#create"
patch ":id", to: "users#update"
delete ":id", to: "users#delete"
end
end
end
API 実装
さきに users_controller.rb
を載せます。
api/users/users_controller.rb
class Api::Users::UsersController < ApplicationController
def index
user = User.ms_search(query_param)
render json: user,
root: 'data',
adapter: :json
end
def create
user = User.create!(required_params)
render json: user,
root: 'data',
adapter: :json
end
def update
user = User.find(params[:id])
user.update!(required_params)
render json: user,
root: 'data',
adapter: :json
end
def delete
user = User.find(params[:id])
user.destroy!
render json: user,
root: 'data',
adapter: :json
end
private
def query_param
return "" if params[:q].blank?
params[:q]
end
def required_params
params.require(:user).permit(:user_system_id, :name, :name_ruby, :url)
end
end
index について
エンドポイントは api/users
で GET メソッドで呼び出された際に実行されます。
クエリパラメータとして q
を渡し、検索ワードとして User.ms_search
メソッドの引数として利用されます。
q
が渡されなかった場合は、空文字を検索ワードとして渡すように query_param
メソッドで制御しています。
疎通確認
curl -X GET "localhost:3000/api/users?q=100006"
# => [
# {
# "data": {
# "id":100006,
# "user_system_id":"",
# "name":"updated_post_name",
# "name_ruby":"updated_post_name"...
# }
# }...
# ]
create について
エンドポイントは api/users
で POST メソッドで呼び出された際に実行されます。
users
テーブルにレコードが作成され、Meilisearch
側の User
インデックスにもドキュメントが新しく作成されます。
疎通確認
curl \
-X POST http://localhost:3000/api/users \
-d '{"user_system_id": "", "name": "post_name", "name_ruby": "post_name", "url": "test@example.com"}' \
-H "Content-Type: application/json"
# => {
# "data": {
# "id":100007,
# "user_system_id":"",
# "name":"post_name",
# "name_ruby":"post_name", ...
# }
# }
Meilisearch
のプレビュー画面でも確認する。
右上にあるインデックス選択ボックスにドキュメントの総数が表示されているので、増減を確認することができます。
update について
エンドポイントは api/users/{任意のid}
で PATCH メソッドで呼び出された際に実行されます。
users
テーブルの特定レコードが更新され、Meilisearch
側の User
インデックスのプライマリーキーが {任意のid}
となっているドキュメントも更新されます。
疎通確認
curl -X PATCH http://localhost:3000/api/users/100007 \
-d '{"name": "updated_post_name", "name_ruby": "updated_post_name"}' \
-H "Content-Type: application/json"
# => {
# "data": {
# "id":100007,
# "user_system_id":"",
# "name":"updated_post_name",
# "name_ruby":"updated_post_name", ...
# }
# }
create
のときと同様に、Meilisearch
のプレビュー画面で確認することができます。
delete について
エンドポイントは api/users/{任意のid}
で DELETE メソッドで呼び出された際に実行されます。
users
テーブルの特定レコードが削除され、Meilisearch
側の User
インデックスのプライマリーキーが {任意のid}
となっているドキュメントも削除されます。
疎通確認
curl -X DELETE http://localhost:3000/api/users/100007 \
-H "Content-Type: application/json"
# => {
# "data": {
# "id":100007,
# "user_system_id":"",
# "name":"updated_post_name",
# "name_ruby":"updated_post_name", ...
# }
# }
create
のときと同様に、Meilisearch
のプレビュー画面で確認することができます。
検索に出てこなくなるのでわかりにくいですが、右上にあるインデックス選択ボックスにドキュメントの総数が表示されているので、増減を確認することができます。
さいごに
前回も書きましたが、やっぱり自動的にインデックスを同期する機能がうれしいです。
今回は、meilisearch-rails
の最低限の機能を使ってみましたが、実際の開発で使用するとなると以下のようなこともしたくなります。
- 検索フィールドの指定
- 例) name フィールドを指定して検索する
- 今回使用した users テーブルに限らずですが、文字列としては似がちになるが意味は全く異なるデータ(名前と都道府県とか、メールアドレスのドメインとブログ URL のドメインとか)が、同一ドキュメントに存在する仕様は避けられないと思います。
そうした場合、全てのフィールドを指定して検索してしまうと、東京都のユーザーを検索したいのに「東さん」がヒットしてしまったり、@gmail.com
アドレスのユーザーを検索したいのに、foobar.com
ブログを運営しているユーザーがヒットしてしまったりします。
なので、この点を考慮する必要はあるかなと思います。
- 条件つきインデックス
-
RDB
テーブルの特定フィールドの値によって、Meilisearch
にインデックスするかどうかを決める - 例) status フィールドの値が active のレコードのみインデックスする
-
meilisearch-sdk
の魅力として、自動インデックス機能を挙げていました。
しかし、実際の users テーブルには、アカウントの有効・無効を示すフィールドであったり、posts テーブルで記事の公開・非公開を示すフィールドであったりと、レコードの状態を示すフィールドがある場合があります。
そのような場合、アカウント無効のデータや下書き中の記事は検索対象にしたくない場合もあり、その場合はそもそもインデックスしたくないです。
この場合、meilisearch-sdk
には条件つきインデックスを制御することができる機能があるので活用したいです。
これらはぱっと思いついただけで、他にもいろいろと考慮したいことがたくさんあると思います。
都度調べて記事に残していきたいと思います。
参考
Discussion