前書き
プログミングスクールに通い始めて2ヶ月ほどが経過しました。
そんな私が、railsを学習する中で気になった技術を見たので実際に実装も兼ねて、学習内容を記事にします。
この記事は、rails APIとは?となっている初学者に向けた記事です。
自分への復習としても兼ねております。
Rails APIモードとは?
RailsのAPIモードは、WebアプリケーションフレームワークRuby on Railsの軽量バージョンで、APIサーバーとしての開発に特化したモードです。通常のRailsアプリケーションでは、ビュー(HTMLやCSS)やフロントエンドのテンプレートエンジンが含まれていますが、APIモードではこれらが不要となるため、効率的で軽量なAPI開発が可能になります。
特徴
1. ビュー関連の不要な機能が省略
APIモードでは、HTMLテンプレートやJavaScript、CSSを扱う機能が省略され、JSON形式でデータを返すAPI開発に特化しています。
ActionController::APIを継承したコントローラーを利用するため、余計な機能が削除されています。
2.軽量で高速
ビューやフロントエンドに関連する部分が排除されているため、メモリ消費が少なく、リクエストの処理速度も向上します。
3.JSONデータをデフォルトで返す
APIモードでは、レスポンスとしてJSONデータを返すのが標準的な設定になっています。クライアント(例:React、Vue.js、モバイルアプリなど)にデータを渡す際に便利です。
4.専用のジェネレーター
rails newコマンドに--apiオプションを付けてプロジェクトを作成すると、APIモード専用の設定が適用されます。
・ビュー関連のGemや設定が省略される。
・ActionController::APIを基盤としたコントローラーが生成される。
rails new my_api_app --api
#通常のコントローラー
class ApplicationController < ActionController::Base
end
#APIモードのコントローラー
class ApplicationController < ActionController::API
end
主な利点
1.ビューが不要な場合に便利
ReactやVue.jsなど、フロントエンドが別途用意されているプロジェクトでは、RailsをAPI専用として利用できます。
2.バックエンドの専用サーバーに最適
モバイルアプリやフロントエンドアプリケーションにデータを提供するAPIサーバーとして最適です。
3.コードがシンプル
必要最低限の機能しか含まれないため、コードがシンプルになります。
使い方例
【前提】
project
|-----frontディレクトリ
| |-----index.html
| |-----script.js
|
|-----railsディレクトリ(rails new アプリ名 --apiで作成したディレクトリ)
・Userモデル
nameカラム emailカラムを設定しています。
【設定】
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins "*"
resource "*",
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
このファイルは--apiで作成した際にデフォルトで作成されているはずです。
コメントアウトされているので上記の部分のコメントアウト部分を外します。
記述内容の詳細は省きますが、ドメインやリソース等の設定行っています。
今回は "*" とすることで、全てを許可する設定にしています。
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
resources :users, only: [:index, :show, :create, :update, :destroy]
end
end
end
名前空間を使ってネストすることで将来的に異なるバージョンのAPIをサポートする際に、バージョンごとに異なるルートを定義することができます。
GET /api/v1/users (index)
GET /api/v1/users/:id (show)
POST /api/v1/users (create)
PUT /api/v1/users/:id (update)
DELETE /api/v1/users/:id (destroy)
この設定により、API のバージョン 1 において、ユーザーリソースに対する基本的な CRUD 操作がサポートされます。
class Api::V1::UsersController < ApplicationController
def index
users = User.all
render json: users
end
def show
user = User.find(params[:id])
render json: user
end
def create
user = User.new(user_params)
if user.save
render json: user, status: :created
else
render json: { errors: user.errors.full_messages }, status: :unprocessable_entity
end
end
def update
user = User.find(params[:id])
if user.update(user_params)
render json: user
else
render json: { errors: user.errors.full_messages }, status: :unprocessable_entity
end
end
def destroy
user = User.find(params[:id])
user.destroy
render json: { message: 'User deleted successfully' }
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
おおよそ通常railsのCRUD操作の記述内容と同じにしています。
render json: users
は、users 変数に格納されているデータを JSON 形式に変換し、それを HTTP レスポンスのボディとしてクライアントに送信します。これにより、クライアントはユーザー情報を JSON 形式で受け取ることができます。
status: :created
は、リソースの作成が成功したことを示すために使用されるステータスコードです。
json: { errors: user.errors.full_messages }
は、user オブジェクトのエラーメッセージを JSON 形式で返すことを示しています。user.errors.full_messages
は、user オブジェクトのバリデーションエラーのメッセージを配列として取得します。これにより、クライアントはどのフィールドがどのようにバリデーションに失敗したのかを理解することができます。
フロントエンドの記述
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rails API Frontend</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>User List</h1>
<ul id="user-list"></ul>
<h2>Add User</h2>
<form id="add-user-form">
<input type="text" id="user-name" placeholder="Name" required>
<input type="email" id="user-email" placeholder="Email" required>
<button type="submit">Add User</button>
</form>
<script src="script.js"></script>
</body>
</html>
scriptタグでscipt.jsを読み込んでいます。
const apiBaseUrl = 'http://localhost:3000/api/v1/users';
// Rails APIのURL
// ユーザー一覧を取得して表示
async function fetchUsers() {
//非同期処理を行う関数を定義
const response = await fetch(apiBaseUrl);
//fetchでapiBaseUrlのURLにGETリクエストを送信して返ってきたデータ全体をresponseに代入
const users = await response.json();
//responseのデータをjson形式に変換してusersに代入
const userList = document.getElementById('user-list');
//HTMLのIDがuser-listの要素を取得してuserListに代入
userList.innerHTML = '';
// リストを初期化
users.forEach(user => {
//forEachメソッドでusersの中身を一つずつ取り出し、userに代入
const li = document.createElement('li');
//liタグを作成してliに代入
li.textContent = `${user.name} (${user.email})`;
//作成したliタグの中に取得したuserのnameとemailを表示
const editLink = document.createElement('a');
//aタグを作成してeditLinkに代入
editLink.href = `edit.html?id=${user.id}`;
// editLinkにhref属性を付与し、URLクエリパラメーターとしてユーザーIDを設定
editLink.textContent = 'Edit';
//editlinkをEditとして設定
li.appendChild(editLink);
//li要素の一番最後にeditlinkを子要素として追加
userList.appendChild(li);
//userListの一番最後にliタグを子要素として追加
});
}
// 新しいユーザーを追加
async function addUser(event) {
//addUser関数にevent引数を持たせる
event.preventDefault();
//ページのリロードを防ぐ
const name = document.getElementById('user-name').value;
//HTMLのIDがuser-nameの要素に入力されたvalue(値)をnameに代入
const email = document.getElementById('user-email').value;
//HTMLのIDがuser-emailの要素に入力されたvalue(値)をemailに代入
const response = await fetch(apiBaseUrl, {
method: 'POST',
//POSTリクエストを指定
headers: {
'Content-Type': 'application/json',
},
//サーバーに送信するデータがjsonだと通知
body: JSON.stringify({ name, email }),
//サーバーにデータの中身を設定
});
if (response.ok) {
//fetchで送ったHTTPレスポンスが200番台(成功)だった場合
document.getElementById('add-user-form').reset();
//HTMLのIDがadd-user-nameのフォーム要素をリセット(初期状態に戻す)
fetchUsers();
// 上記で定義したfetchUsers関数を呼び出し
} else {
//成功しなかった場合(成功以外)
const error = await response.json();
//失敗した場合は、サーバーから失敗の内容をjson形式に変換してerrorに代入
alert(`Error: ${error.errors.join(', ')}`);
//アラートダイアログでeroorの中のerrorsプロパティをカンマで繋げて出力
}
}
// イベントリスナーを設定
document.getElementById('add-user-form').addEventListener('submit', addUser);
// ページ初期化時にユーザー一覧を取得
fetchUsers();
今回script.jsにはuserの一覧取得と新規作成の記述しかしておりません(長くなるため)
まとめ
このように、scriptの関数の中でrailsサーバーと通信してデータのやり取りをすることができます。
これまではrailsの中にjavascriptを埋め込んで操作したりを学んできましたが、開発現場によっては外部のファイルにrails APIを連携して使えるということを学びました。