Contents
1️⃣ 環境構築と Rails API プロジェクトの作成
この章では、現在公式にリリースされている安定版(Ruby 3.2 系、Rails 7.2 系)を前提に、ローカル環境へのインストール手順と rails new --api で API‑only アプリケーションを作成する流れを解説します。
なぜ公式版を使うことが重要か → 将来のアップデートやセキュリティパッチが確実に提供されるため。
本章の結論 → rbenv(または RVM)でバージョン管理し、Docker・GitHub Actions と組み合わせた開発基盤をすぐに構築できる。
1.1 Ruby と Rails のインストール
📦 必要なツール
| ツール | 用途 | 推奨インストール方法 |
|---|---|---|
| rbenv | Ruby バージョン管理 | macOS: brew install rbenv Ubuntu: 手動 Git クローン(後述) |
| Bundler | Gem の依存解決 | gem install bundler |
| Rails | アプリケーションフレームワーク | gem install rails -v "~> 7.2" |
🛠 Ubuntu における rbenv の正しいインストール手順
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 必要なビルドツールを取得 sudo apt-get update && sudo apt-get install -y \ build-essential libssl-dev libreadline-dev zlib1g-dev git # rbenv 本体と ruby-build プラグインを Git からクローン git clone https://github.com/rbenv/rbenv.git ~/.rbenv cd ~/.rbenv && src/configure && make -C src git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build # シェル設定を追加(~/.bashrc か ~/.zshrc に追記) echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc echo 'eval "$(rbenv init -)"' >> ~/.bashrc source ~/.bashrc |
参考: rbenv 公式インストール手順 https://github.com/rbenv/rbenv#basic-github-checkout
🚀 Ruby と Rails の導入
|
1 2 3 4 5 6 7 8 9 |
# 最新の安定版 Ruby をインストール(例: 3.2.2) rbenv install 3.2.2 rbenv global 3.2.2 # Bundler と Rails をインストール gem install bundler gem install rails -v "~> 7.2" rbenv rehash |
これで ruby -v と rails -v がそれぞれ 3.2.x、7.2.x と表示されれば完了です。
1.2 API‑only プロジェクトの作成
📂 コマンドと生成結果
|
1 2 3 4 |
# PostgreSQL をデータベースに指定し、API モードで新規プロジェクトを作成 rails new my_api --api -d postgresql cd my_api |
ポイント:
--apiオプションはビュー・アセット系のディレクトリを省き、軽量な API 用テンプレートだけを生成します。
📁 主要ディレクトリ構造(抜粋)
|
1 2 3 4 5 6 7 8 9 |
my_api/ ├─ app/ │ ├─ controllers/ # API コントローラのみ │ └─ serializers/ # jsonapi‑serializer 用シリアライザ ├─ config/ │ ├─ database.yml # PostgreSQL 設定(環境変数推奨) │ └─ routes.rb # /api/v1/... のスコープを設定 └─ Gemfile |
出典:Rails Guides – API Mode https://guides.rubyonrails.org/api_app.html
2️⃣ 必須 Gem と JSON:API 準拠実装
この章では、JSON:API に準拠したシリアライザ・コントローラの雛形を提供する 主要 Gem を紹介し、実際にコードへ落とし込む手順を示します。
目的 → データ構造の一貫性とクライアント側の開発負荷低減。
結論 → jsonapi-serializer と組み合わせるだけで、ほぼ自動的に規格通りの JSON が生成できます。
2.1 Gem の選定とインストール
| Gem | 主な機能 | 設定手順 |
|---|---|---|
| jsonapi-serializer | JSON:API 準拠シリアライザ | bundle add jsonapi-serializer |
| rswag | Swagger (OpenAPI) のテスト駆動生成 | bundle add rswag → rails generate rswag:install |
| devise, devise-jwt | 認証基盤 + JWT 発行 | bundle add devise devise-jwt |
| rack-cors | CORS ヘッダ制御 | bundle add rack-cors |
| kaminari | ページネーション | bundle add kaminari |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# Gemfile への追記例(手動でも可) gem "jsonapi-serializer" gem "rswag" gem "devise" gem "devise-jwt" gem "rack-cors" gem "kaminari" group :development, :test do gem "rspec-rails" gem "factory_bot_rails" end bundle install |
参考:各 Gem の公式リポジトリ(例: jsonapi‑serializer https://github.com/jsonapi-serializer/jsonapi-serializer)
2.2 JSON:API 準拠シリアライザとコントローラ実装例
📄 ArticleSerializer(シリアライザ)
|
1 2 3 4 5 6 7 8 |
# app/serializers/article_serializer.rb class ArticleSerializer include JSONAPI::Serializer attributes :title, :content, :published_at belongs_to :author, record_type: :user end |
🛠 ArticlesController(API コントローラ)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# app/controllers/api/v1/articles_controller.rb module Api module V1 class ArticlesController < ApplicationController before_action :authenticate_user! # devise-jwt が提供するヘルパー before_action :set_article, only: %i[show update destroy] def index articles = Article.order(created_at: :desc).page(params[:page]).per(10) render json: ArticleSerializer.new( articles, meta: { pagination: pagination_meta(articles) } ) end def show render json: ArticleSerializer.new(@article) end # create / update / destroy は省略(標準的な実装例は公式ドキュメント参照) private def set_article @article = Article.find(params[:id]) end def pagination_meta(collection) { current_page: collection.current_page, next_page: collection.next_page, prev_page: collection.prev_page, total_pages: collection.total_pages, total_count: collection.total_count } end end end end |
出典:jsonapi‑serializer README https://github.com/jsonapi-serializer/jsonapi-serializer#basic-usage
3️⃣ 認証・認可と CORS 設定
API の安全性を担保するために JWT 認証 と CORS 制御 を必ず実装します。ここでは devise-jwt によるシンプルなトークンベース認証、OAuth2 の代替オプション(Doorkeeper)、そして rack-cors の設定例を示します。
3.1 JWT 認証(devise‑jwt)実装手順
🔧 前提条件
deviseとdevise-jwtが Gemfile に追加済みであること。Userモデルが Devise の標準モジュールを持つこと。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# app/models/user.rb class User < ApplicationRecord devise :database_authenticatable, :registerable, :jwt_authenticatable, jwt_revocation_strategy: JwtDenylist end # app/models/jwt_denylist.rb class JwtDenylist < ApplicationRecord include Devise::JWT::RevocationStrategies::Denylist self.table_name = 'jwt_denylists' end |
|
1 2 3 4 |
# JWT ディナイリスト用テーブルを作成 rails generate migration CreateJwtDenylists jti:string:index exp:datetime rails db:migrate |
⚙️ Devise 初期設定(抜粋)
|
1 2 3 4 5 6 7 8 9 10 |
# config/initializers/devise.rb Devise.setup do |config| config.jwt do |jwt| jwt.secret = Rails.application.credentials.dig(:jwt, :secret) jwt.dispatch_requests = [['POST', %r{^/api/v1/sign_in$}]] jwt.revocation_requests = [['DELETE', %r{^/api/v1/sign_out$}]] jwt.expiration_time = 2.hours.to_i end end |
📡 認証コントローラ例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# app/controllers/api/v1/auth_controller.rb module Api module V1 class AuthController < ApplicationController skip_before_action :authenticate_user!, only: %i[sign_in sign_up] def sign_up user = User.new(user_params) if user.save render json: { message: 'User created' }, status: :created else render json: { errors: user.errors.full_messages }, status: :unprocessable_entity end end def sign_in user = User.find_by(email: params[:email]) if user&.valid_password?(params[:password]) # devise-jwt が自動で Authorization ヘッダに JWT をセット render json: { message: 'Signed in' } else render json: { error: 'Invalid credentials' }, status: :unauthorized end end private def user_params params.permit(:email, :password, :password_confirmation) end end end end |
参考:devise‑jwt README https://github.com/waiting-for-dev/devise-jwt
3.2 OAuth2 の代替オプション(Doorkeeper)
| 項目 | 説明 |
|---|---|
| 用途 | 複数クライアント・スコープ管理が必要な B2B サービス向け |
| 導入手順 | gem "doorkeeper" → bundle install → rails generate doorkeeper:install → rails db:migrate |
| ポイント | resource_owner_authenticator に Devise ロジックを流用すれば、既存ユーザーデータベースと統合可能 |
出典:Doorkeeper 公式ガイド https://doorkeeper.gitbook.io/guides/
3.3 CORS 設定(rack‑cors)
📄 config/initializers/cors.rb
|
1 2 3 4 5 6 7 8 9 10 11 |
Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins 'https://frontend.example.com', 'https://app.staging.example.com' resource '/api/*', headers: :any, expose: ['Authorization'], methods: %i[get post put patch delete options head], max_age: 600 end end |
- ポイント:
originsは本番環境・ステージング環境に合わせて変更してください。 - 注意:ワイルドカード
*は開発時以外は使用しないことがベストプラクティスです。
参考:rack‑cors GitHub https://github.com/cyu/rack-cors
4️⃣ テスト自動化・CI/CD と Docker 開発環境
品質保証とデプロイの高速化は実務で欠かせません。ここでは RSpec + FactoryBot によるテスト基盤、GitHub Actions を用いた CI パイプライン、そして Docker / docker‑compose で統一ローカル環境を構築する手順を示します。
4.1 RSpec と factory_bot のセットアップ
📦 必要な Gem(すでに Gemfile に追加済み)
|
1 2 3 |
gem "rspec-rails" gem "factory_bot_rails" |
|
1 2 3 |
# 初期化コマンド bundle exec rails generate rspec:install |
🧪 サンプルリクエストスペック
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# spec/requests/api/v1/articles_spec.rb require 'rails_helper' RSpec.describe "Articles API", type: :request do let!(:user) { create(:user) } let!(:articles) { create_list(:article, 3, author: user) } let(:headers) { { "Authorization" => "Bearer #{user.jwt}" } } describe "GET /api/v1/articles" do before { get "/api/v1/articles", headers: headers } it "returns status 200" do expect(response).to have_http_status(200) end it "responds with JSON:API format" do json = JSON.parse(response.body) expect(json["data"].size).to eq(3) expect(json["data"].first["type"]).to eq("articles") end end end |
出典:RSpec Rails 公式ガイド https://relishapp.com/rspec/rspec-rails/docs
4.2 GitHub Actions による CI パイプライン
📄 .github/workflows/ci.yml(主要ステップ)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
name: CI on: push: branches: [main] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest services: db: image: postgres:15 env: POSTGRES_USER: postgres POSTGRES_PASSWORD: password POSTGRES_DB: my_api_test ports: ['5432:5432'] options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v3 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: '3.2' # 現行安定版 - name: Install dependencies run: | gem install bundler bundle config set --local without 'development' bundle install --jobs 4 --retry 3 - name: Run RuboCop (Lint) run: bundle exec rubocop - name: Run Brakeman (Security Scan) run: bundle exec brakeman -q -w2 - name: Prepare test DB env: DATABASE_URL: postgres://postgres:password@localhost:5432/my_api_test run: | bundle exec rails db:create db:schema:load --trace - name: Run RSpec run: bundle exec rspec |
ポイント:
ruby-versionはローカルで使用しているバージョンと合わせることで、環境差異を減らします。
4.3 Dockerfile と docker‑compose による統一開発環境
📦 Dockerfile(Node.js のパッケージ名に注意)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# Dockerfile FROM ruby:3.2-slim # Node.js (npm) と Yarn をインストール RUN apt-get update -qq && \ # Debian 系では `nodejs` が公式パッケージ、Ubuntu 20.04+ でも同名 apt-get install -y --no-install-recommends \ build-essential libpq-dev nodejs npm && \ npm install -g yarn && \ rm -rf /var/lib/apt/lists/* # 作業ディレクトリ作成 WORKDIR /app # Gemfile と lockfile を先にコピーしてキャッシュを有効化 COPY Gemfile* ./ RUN gem install bundler && bundle config set --local without 'development test' && \ bundle install --jobs 4 --retry 3 # アプリ全体をコピー COPY . . EXPOSE 3000 CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"] |
🐳 docker-compose.yml(開発用)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
version: '3.9' services: db: image: postgres:15-alpine environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: password POSTGRES_DB: my_api_development volumes: - pgdata:/var/lib/postgresql/data web: build: . command: bundle exec rails s -p 3000 -b '0.0.0.0' environment: DATABASE_URL: postgres://postgres:password@db:5432/my_api_development RAILS_ENV: development ports: - "3000:3000" depends_on: - db volumes: pgdata: |
使用方法
bash
docker compose up --build # 初回ビルド+起動
docker compose exec web rails db:create db:migrate # DB 初期化
5️⃣ OpenAPI/Swagger ドキュメント公開と本番デプロイ・バージョニング戦略
この最終章では、テスト駆動型ドキュメント生成 (rswag) と バージョニングのベストプラクティス、そして Docker イメージをそのまま Fly.io / Render / Railway にデプロイ する流れをまとめます。
5.1 rswag による Swagger UI の自動生成
📄 spec/integration/articles_spec.rb(rswag DSL)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
require 'swagger_helper' RSpec.describe 'Articles API', type: :request do path '/api/v1/articles' do get '取得 (一覧)' do tags 'Articles' produces 'application/vnd.api+json' parameter name: :page, in: :query, type: :integer, description: 'ページ番号' response '200', 'articles list' do schema '$ref' => '#/components/schemas/articles' run_test! end end post '作成' do tags 'Articles' consumes 'application/vnd.api+json' parameter name: :article, in: :body, schema: { type: :object, properties: { data: { type: :object, properties: { type: { type: :string, example: 'articles' }, attributes: { type: :object, properties: { title: { type: :string }, content: { type: :string } }, required: %w[title content] } }, required: %w[type attributes] } }, required: ['data'] } response '201', 'article created' do let(:article) { { data: { type: 'articles', attributes: { title: 'Test', content: 'Body' } } } } run_test! end end end end |
|
1 2 3 4 5 6 |
# Swagger JSON を生成し、UI をマウント rails rswag:specs:swaggerify # → swagger/v1/swagger.json が作成される # routes.rb に以下を追記 mount Rswag::Ui::Engine => '/api-docs' mount Rswag::Api::Engine => '/api-docs' |
出典:rswag 公式リポジトリ https://github.com/rswag/rswag
5.2 API バージョニング戦略
| 手法 | メリット | デメリット |
|---|---|---|
URI ベース (/api/v1/...) |
可視性が高く、外部ドキュメントと整合しやすい。 | エンドポイントが増えると URL が長くなる。 |
ヘッダー方式 (Accept: application/vnd.myapp.v2+json) |
同一エンドポイントで複数バージョンを同時提供可能。 | クライアント実装がやや複雑になる。 |
推奨実装(URI + ヘッダー併用)
|
1 2 3 4 5 6 7 8 9 10 11 12 |
# config/routes.rb Rails.application.routes.draw do scope module: :api, path: '/api', defaults: { format: :json } do namespace :v1 do resources :articles end # 将来的にヘッダー版 v2 を追加したいときのフォワード例 match '*path', to: 'versioning#dispatch', via: :all end end |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# app/controllers/api/versioning_controller.rb module Api class VersioningController < ApplicationController def dispatch version = request.headers['Accept']&.match(/vnd\.myapp\.v(\d+)\+json/) { |m| m[1] } if version == '2' # v2 用コントローラへ内部リダイレクト(例: ArticlesV2Controller) redirect_to controller: "api/v2/articles", action: request.method_symbol, params: request.path_parameters else render json: { error: 'Unsupported API version' }, status: :bad_request end end end end |
参考:API バージョニングベストプラクティス(Google Cloud) https://cloud.google.com/apis/design/versioning
5.3 Docker イメージをそのまま Fly.io / Render / Railway にデプロイ
📦 共通前提
Dockerfileが マルチステージ で不要なビルド依存を除去済み。- 環境変数は各プラットフォームのシークレット管理機能で設定する。
Fly.io 用 fly.toml の最小構成
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# fly.toml app = "my-api-app" primary_region = "nrt" # 東京リージョン例 [build] image = "docker.io/library/my_api:latest" [env] RAILS_MASTER_KEY = "${RAILS_MASTER_KEY}" DATABASE_URL = "postgres://postgres:${POSTGRES_PASSWORD}@${DATABASE_HOST}:${DATABASE_PORT}/my_api_production" [[services]] internal_port = 3000 protocol = "tcp" ports = [{ port = 80 }, { port = 443, handlers = ["tls"] }] |
デプロイ手順(Fly.io)
|
1 2 3 4 5 6 7 8 9 10 |
# Docker イメージをローカルでビルド(CI が自動化可) docker build -t my_api:latest . # Fly.io にログインし、アプリ作成 flyctl auth login flyctl launch --copy-config # 既存 fly.toml を利用 # デプロイ実行 flyctl deploy |
Render と Railway は GitHub リポジトリを接続 → Dockerfile を自動検出 の流れで同様にデプロイ可能です。シークレットは各 UI から RAILS_MASTER_KEY・DATABASE_URL 等を設定してください。
参考:Fly.io デプロイガイド https://fly.io/docs/getting-started/rails/
まとめ
| セクション | キーアクション |
|---|---|
| 環境構築 | rbenv → Ruby 3.2、Rails 7.2 をインストールし rails new --api で軽量プロジェクトを作成 |
| 主要 Gem | jsonapi‑serializer・rswag・devise‑jwt・rack‑cors・kaminari を導入して JSON:API と認証基盤を構築 |
| 認証 & CORS | JWT 認証実装例、OAuth2 の代替(Doorkeeper)、安全な CORS ポリシー設定 |
| テスト・CI | RSpec + FactoryBot、GitHub Actions に Lint・Security Scan・RSpec を組み込み |
| Docker & CI/CD | Dockerfile(Node.js パッケージ名に注意)+ docker‑compose でローカル統一環境を提供 |
| ドキュメント & デプロイ | rswag によるテスト駆動型 Swagger、URI + ヘッダー併用バージョニング、Fly.io/Render/Railway へのコンテナデプロイ |
上記手順を踏むことで、「公式安定版」+「テスト駆動」+「Docker 化」 の三位一体の開発フローが完成します。これにより、コード品質・セキュリティ・デプロイ速度すべてで実務レベルの要件を満たした 本番環境対応 Rails API が迅速に構築できます。
参考文献
- rbenv 公式インストール手順 – https://github.com/rbenv/rbenv#basic-github-checkout
- Ruby on Rails Guides – API Mode – https://guides.rubyonrails.org/api_app.html
- jsonapi‑serializer GitHub – https://github.com/jsonapi-serializer/jsonapi-serializer
- devise‑jwt README – https://github.com/waiting-for-dev/devise-jwt
- Doorkeeper 公式ガイド – https://doorkeeper.gitbook.io/guides/
- rack‑cors GitHub – https://github.com/cyu/rack-cors
- RSpec Rails Documentation – https://relishapp.com/rspec/rspec-rails/docs
- rswag 公式リポジトリ – https://github.com/rswag/rswag
- API バージョニングベストプラクティス (Google Cloud) – https://cloud.google.com/apis/design/versioning
- Fly.io Rails デプロイガイド – https://fly.io/docs/getting-started/rails/