---
title: "Rails APIとは？作成手順・JWT認証・React連携・Docker環境を実装解説【Rails 8.1】"
url: "https://www.issoh.co.jp/tech/details/2905/"
published: 2024-07-03
updated: 2026-10-12
categories: ["Ruby on Rails"]
publisher: "株式会社一創"
---

# Rails APIとは？作成手順・JWT認証・React連携・Docker環境を実装解説【Rails 8.1】

Rails APIは、Ruby on Railsをビュー層のない「APIモード」で動かし、JSONを返すバックエンドに特化させた構成を指します。ReactやVueと組み合わせたSPA、モバイルアプリのバックエンド、マイクロサービスで採用されます。本記事はRails 8.1系を前提に、**API作成の手順・JSONの整形・JWT認証・ReactとのCORS連携・Docker Composeでの開発環境構築・API仕様書の自動生成**までを、動くコードで一気通貫に解説します。とくにReactとの連携で詰まりやすいCORSと、独学者が最短で環境を立ち上げるDocker構成は、コピーして動かせる形で示します。

## まとめ：Rails APIの要点

- **APIモードとは**：`rails new アプリ名 --api` でビュー・不要ミドルウェアを省いた軽量構成。既存アプリは `config.api_only = true` で切り替える。
- **作成の骨格**：`api/v1` 名前空間でRESTfulにルーティングし、コントローラで `render json:` を返す。整形は標準の `as_json`、規模が出たら jbuilder か alba を使う（active\_model\_serializersはメンテナンスモード）。
- **認証**：`devise-jwt` でJWTを発行し、フロントはヘッダに `Authorization: Bearer` を付与。トークンの保存先はXSS/CSRFのリスクと引き換えで選ぶ。
- **React連携の要**：別オリジンになるため `rack-cors` でCORSを許可する。`--api` なら `config/initializers/cors.rb` が生成済み（コメントアウト状態）。
- **開発環境**：Docker Composeで DB・Rails API・React を3コンテナに分けると、独学でもOSに依存せず同じ環境を再現できる。
- **バージョン**：APIモードはRails 5.0で標準化。本記事は執筆時点の最新安定版 Rails 8.1系を前提とする。

## Rails APIとは｜APIモードと通常モードの違い

Rails APIモードは、HTMLビューを描画しないでJSONなどのデータだけを返すことに特化したRailsの動作モードです。通常モードが完全なMVC（Model-View-Controller）を備えるのに対し、APIモードはViewとブラウザ向けミドルウェアを省いた分だけ軽く、起動と応答が速くなります。

### APIモードで省かれるもの

APIモードでは、ブラウザのセッションやCookie、Flash、アセットパイプライン、ビューのレンダリングに関わるミドルウェアが既定で外れます。具体的には、Cookieやセッション関連のミドルウェア、`ActionDispatch::Flash`、静的ファイル配信などが読み込まれず、`ApplicationController` は `ActionController::Base` ではなく `ActionController::API` を継承します。この差がリクエスト処理の軽量化に直結します。

### 通常モードとの使い分け基準

サーバー側でHTMLを組み立てて返す従来型のWebアプリなら通常モードが向きます。一方、フロントをReactやVue、あるいはモバイルアプリが担い、Railsはデータ提供に徹する構成ならAPIモードを選びます。判断の分かれ目は「Railsがビューを描くか否か」の一点で、画面を持たないならAPIモードにする、というのが実務上の基準です。管理画面など一部だけHTMLが必要なら、通常モードのまま `respond_to` でJSONを併用する折衷も可能です。

## Rails APIの作成手順｜rails new –api から最初のエンドポイントまで

ここではRails 8.1系で、記事（Article）を管理する最小のAPIを作ります。プロジェクト作成からエンドポイント公開までの流れは次のとおりです。

### プロジェクトの作成とディレクトリ構成

`--api` オプションを付けて新規作成します。既定のデータベースはSQLiteですが、本番を見据えるなら `-d postgresql` を付けてPostgreSQLにしておくと、後述のDocker構成にもそのまま乗ります。

```
rails new blog_api --api -d postgresql
cd blog_api
rails generate model Article title:string body:text
rails db:create db:migrate
```

モデル・コントローラ・マイグレーションの生成は `rails generate` が担います。scaffoldやカスタムジェネレータを含む使い分けは[Railsジェネレータ（rails generate）の使い方](https://www.issoh.co.jp/tech/details/2874/)で詳しく整理しています。

### ルーティングとコントローラの実装

APIはバージョンを切って壊れにくくするのが定石です。`api/v1` の名前空間でRESTfulなルートを定義します。

```
# config/routes.rb
Rails.application.routes.draw do
  namespace :api do
    namespace :v1 do
      resources :articles
    end
  end
end
```

この1行の `resources :articles` だけで、一覧・詳細・作成・更新・削除に対応する `/api/v1/articles` 系のエンドポイントが揃います。対応するコントローラを作り、JSONを返します。

```
rails generate controller api/v1/articles
```

```
# app/controllers/api/v1/articles_controller.rb
module Api
  module V1
    class ArticlesController < ApplicationController
      def index
        render json: Article.all
      end

      def show
        render json: Article.find(params[:id])
      end

      def create
        article = Article.new(article_params)
        if article.save
          render json: article, status: :created
        else
          render json: { errors: article.errors }, status: :unprocessable_entity
        end
      end

      private

      def article_params
        params.require(:article).permit(:title, :body)
      end
    end
  end
end
```

存在しないIDへのアクセスは `ActiveRecord::RecordNotFound` を送出します。APIでは例外を握りつぶさず、`rescue_from` で404 JSONに変換しておくと、フロント側のエラー処理が安定します。

```
# app/controllers/application_controller.rb
class ApplicationController < ActionController::API
  rescue_from ActiveRecord::RecordNotFound do |e|
    render json: { error: e.message }, status: :not_found
  end
end
```

### 既存アプリをAPIモードへ切り替える

すでにあるRailsアプリをAPI寄りにするには、`config/application.rb` に1行加えます。ただし途中からの切り替えはビュー依存コードの棚卸しが必要になるため、実際は新規を `--api` で作り直すほうが早いケースが多いです。

```
# config/application.rb
module BlogApi
  class Application < Rails::Application
    config.api_only = true
  end
end
```

### JSONレスポンスの整形とシリアライザの選定

小規模なうちは `render json:` と `as_json` のオプション（`only`/`except`/`include`）で十分です。ネストや条件分岐が増えたら専用のシリアライザを導入しますが、ここで選択を誤ると保守が重くなります。2026年時点の実情を踏まえた判断は次のとおりです。

| 手段                         | 位置づけ           | 向く場面            |
| -------------------------- | -------------- | --------------- |
| as\_json / render json:    | Rails標準        | 属性が少なく整形が単純     |
| jbuilder                   | Rails同梱（通常モード） | ビューとしてJSONを書きたい |
| alba                       | 活発に開発中・高速      | 新規で本格的な整形が必要    |
| active\_model\_serializers | メンテナンスモード      | 既存資産の踏襲のみ       |

結論として、新規プロジェクトで `active_model_serializers` を選ぶ理由はほぼありません。0.10系の維持は続くものの新機能開発は止まっており、1.0のリリース予定もないためです。整形ロジックをしっかり書くなら、依存が少なく高速な alba が第一候補になります。`--api` では jbuilder がGemfileに入らないため、jbuilderを使う場合は明示的に追加します。過度な抽象化を避け、まずは標準の `as_json` で始めて、必要になった時点で alba へ寄せる進め方が無駄がありません。既存アプリで `active_model_serializers` を使い続ける場合の導入手順とバージョン境界は、ActiveModelSerializersの使い方｜0.10.16の対応Railsと採用判断にまとめています。

## JWTによるRails API認証の実装｜トークンの発行と保存

APIはCookieセッションに頼れない場面が多く、トークンベースの認証が基本になります。デファクトはJWT（JSON Web Token）で、Railsでは `devise` と `devise-jwt` の組み合わせが手軽です。GSC上でも「railsapi 認証」「react railsapi 認証」の検索が多く、連携でつまずく中心がここです。

### devise-jwt によるトークン発行

GemfileにDevise系を追加し、ユーザーモデルにJWT認証の設定を加えます。ログイン成功時にレスポンスヘッダの `Authorization` にトークンが載り、以降のリクエストはそのトークンで認証します。

```
# Gemfile
gem "devise"
gem "devise-jwt"

# app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :jwt_authenticatable, jwt_revocation_strategy: JwtDenylist
end
```

ログアウトで即時にトークンを無効化したい場合は、失効ストラテジ（上記の `JwtDenylist` など）を用意し、無効化したトークンを記録するテーブルを持たせます。デナイリスト方式では、トークンの識別子 `jti` と有効期限 `exp` を保存するテーブルを作ります。

```
# db/migrate/xxxx_create_jwt_denylists.rb
class CreateJwtDenylists < ActiveRecord::Migration[8.1]
  def change
    create_table :jwt_denylists do |t|
      t.string :jti, null: false
      t.datetime :exp, null: false
    end
    add_index :jwt_denylists, :jti
  end
end
```

ステートレスなJWTでも、こうした失効管理を入れることで「ログアウトしたのにトークンが使える」問題を防げます。

### フロントでのトークン保存とセキュリティ

発行したJWTをReact側のどこに保存するかは、セキュリティ設計の分かれ目です。`localStorage` は実装が簡単な一方、JavaScriptから読めるためXSSでトークンを盗まれるリスクがあります。`HttpOnly` なCookieに置けばJavaScriptから隔離できますが、今度はCSRF対策が必要になります。どちらを選んでも守るべき点が残るため、XSS対策（入力のエスケープ・CSP）とCSRF対策はセットで検討してください。トークンを扱う際の攻撃面は[CSRF（クロスサイトリクエストフォージェリ）とは何か？](https://www.issoh.co.jp/column/details/3984/)で前提を押さえておくと判断しやすくなります。少なくとも、有効期限（`exp`）は短くし、更新にはリフレッシュトークンを別管理するのが安全側の設計です。

## React × Rails API連携｜CORS設定とデータ取得

ReactアプリとRails APIは別ポート（別オリジン）で動くのが普通で、そのままではブラウザがCORS（Cross-Origin Resource Sharing）で通信をブロックします。連携が動かない原因の大半はこのCORS設定漏れです。ここが「react railsapi」系検索の実需の中心でありながら、解説が抜けがちな箇所です。

### rack-cors でCORSを許可する

`--api` で作成したアプリには `config/initializers/cors.rb` が最初から生成されています（全体がコメントアウトされた状態）。Gemfileの `rack-cors` を有効化し、フロントのオリジンを明示して許可します。

```
# Gemfile
gem "rack-cors"

# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins "http://localhost:5173"   # ReactのViteが動くオリジン
    resource "*",
      headers: :any,
      expose: ["Authorization"],       # JWTをヘッダで返すため公開
      methods: [:get, :post, :put, :patch, :delete, :options]
  end
end
```

ポイントは3つです。第一に `insert_before 0` で他ミドルウェアより先に動かすこと。第二に、JWTをヘッダで返すなら `expose` に `Authorization` を含めること。第三に、本番では `origins "*"` を使わず具体的なドメインを列挙することです。認証情報付きのリクエスト（`credentials: true`）はワイルドカードのオリジンと併用できない仕様なので、この点でも本番のオリジンは限定する必要があります。

### React側からのデータ取得とJWT付与

Reactからはfetchでもaxiosでも構いません。ログインで受け取ったトークンを、以降のリクエストの `Authorization` ヘッダに付けます。なお、Reactの新規作成に長く使われた create-react-app は開発が終了しており、現在はViteでの作成が標準です。

```
// 記事一覧の取得（fetch）
const token = localStorage.getItem("token");

const res = await fetch("http://localhost:3000/api/v1/articles", {
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${token}`,
  },
});
const articles = await res.json();
```

APIのURLはコンポーネントに直書きせず、Viteなら `import.meta.env.VITE_API_URL` のように環境変数へ逃がすと、開発と本番でオリジンを切り替えやすくなります。

## DockerでReact＋Rails API開発環境を構築する

「react railsapi docker」「独学 react railsapi」の検索が示すとおり、連携を学ぶ最初の壁は環境構築です。RubyとNode、PostgreSQLをOSに直接入れると、バージョン差で手順が崩れます。Docker Composeで役割ごとにコンテナを分ければ、どのOSでも同じ環境を再現でき、独学でも「動かない」で止まりにくくなります。ここは競合の解説が手薄な領域なので、そのまま使える最小構成を示します。

### 3コンテナ構成のdocker-compose.yml

リポジトリ直下に Rails APIを `api/`、Reactを `front/` として並べたモノレポ構成を前提に、DB（PostgreSQL）、Rails API、Reactフロントの3サービスへ分けます。`compose.yaml` はその直下（`api/` と `front/` と同じ階層）に置きます。

```
# compose.yaml
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: password
    volumes:
      - pg_data:/var/lib/postgresql/data

  api:
    build: ./api
    command: bash -c "bin/rails db:prepare && bin/rails s -b 0.0.0.0"
    volumes:
      - ./api:/app
    ports:
      - "3000:3000"
    depends_on:
      - db

  front:
    build: ./front
    command: npm run dev -- --host
    volumes:
      - ./front:/app
    ports:
      - "5173:5173"

volumes:
  pg_data:
```

APIコンテナの `database.yml` では、接続先ホストを `localhost` ではなくサービス名の `db` にします。コンテナ間はサービス名で名前解決されるためです。ここを `localhost` のままにして接続できない、というのが最頻の詰まりどころです。Docker Composeの仕組みそのものは[docker-composeとは？複数コンテナをymlで定義し一括管理する仕組み](https://www.issoh.co.jp/tech/details/13282/)で基礎から確認できます。

```
# api/config/database.yml（development）
development:
  adapter: postgresql
  host: db
  username: postgres
  password: password
  database: blog_api_development
```

`docker compose up` で3コンテナが起動し、APIは `localhost:3000`、Reactは `localhost:5173` で待ち受けます。前段のCORS設定でReactのオリジン（5173）を許可していれば、この時点で連携が通ります。Dockerを使わずローカルに直接Rails環境を整える場合は、[ruby on rails を vscode で開発する環境構築【2026年版】](https://www.issoh.co.jp/tech/details/2878/)のDev Container構成も選択肢になります。

## API仕様書の自動生成｜rswagでSwagger/OpenAPIを出す

フロントと分業する以上、エンドポイントの仕様書は必須です。手書きは陳腐化するため、テストから仕様を生成する `rswag` を使うと、実装とドキュメントのずれを防げます。生成物はOpenAPI（Swagger）形式で、ブラウザ上のUIから叩いて確認できます。

```
# Gemfile
gem "rswag"
```

```
rails generate rswag:install
```

インストール後、リクエスト仕様（spec）にエンドポイントの入出力を記述し、`rake rswag:specs:swaggerize` を実行すると仕様ファイルが出力されます。仕様がテストとして走るため、レスポンスの構造を変えたのにドキュメントだけ古い、という食い違いが起きにくいのが利点です。

```
# spec/requests/api/v1/articles_spec.rb（抜粋）
require "swagger_helper"

RSpec.describe "api/v1/articles", type: :request do
  path "/api/v1/articles" do
    get "記事一覧を取得" do
      produces "application/json"
      response "200", "articles found" do
        run_test!
      end
    end
  end
end
```

## Rails APIから外部サービスを呼ぶ｜HTTPクライアントとWebhook

Rails APIは、自らエンドポイントを提供するだけでなく、外部サービスのAPIを呼び出すクライアントにもなります。決済（Stripe）、認証連携（OAuth）、通知（Slack）など、他システムとの橋渡しは実務で頻出します。

### HTTPクライアントで外部APIを呼ぶ

外部APIへのリクエストは、標準の `Net::HTTP` のほか、`Faraday` や `HTTParty` が使われます。ミドルウェアで再試行やロギングを差し込める `Faraday` は、外部連携が増えるほど扱いやすくなります。

```
# Gemfile
gem "faraday"

# 例：外部APIからデータ取得
conn = Faraday.new(url: "https://api.example.com")
res = conn.get("/data")
data = JSON.parse(res.body)
```

### Webhook受信と非同期処理

外部サービスからのイベント通知（Webhook）は、`POST` を受けるエンドポイントを用意して処理します。受信ハンドラ内で重い処理を同期実行すると、送信元がタイムアウトして再送を繰り返す原因になります。受信は素早く `200` を返し、実処理はバックグラウンドジョブへ逃がすのが定石です。非同期処理の実装は[Sidekiqとは？Rubyで非同期処理を簡単に実現するバックグラウンドジョブツール](https://www.issoh.co.jp/tech/details/7843/)が参考になります。

```
# config/routes.rb
post "webhooks/receive", to: "webhooks#receive"

# app/controllers/webhooks_controller.rb
class WebhooksController < ApplicationController
  def receive
    event = JSON.parse(request.body.read)
    ProcessWebhookJob.perform_later(event)   # 実処理は非同期へ
    head :ok
  end
end
```

## よくある質問

### Rails APIモードと通常モードはどちらを選ぶべきですか？

Railsがビューを描くなら通常モード、フロントをReactやモバイルアプリに任せてデータだけ返すならAPIモードです。画面を持たないバックエンドはAPIモードにする、と判断すれば大きく外しません。

### Rails APIとReactは同じサーバーで動かせますか？

開発中は別ポート（例：Rails 3000、React 5173）で動かすのが一般的で、その場合はオリジンが異なるため `rack-cors` でのCORS許可が必須です。本番では同一ドメイン配下にリバースプロキシで束ねる構成も取れます。

### Rails APIの認証は何を使えばよいですか？

トークンベースのJWTが標準的で、`devise-jwt` で手軽に実装できます。トークンの保存先（localStorageかHttpOnly Cookieか）はXSS/CSRFのリスクを踏まえて選び、有効期限は短くしてリフレッシュトークンで更新します。

### APIモードはどのRailsバージョンから使えますか？

APIモード（`--api` / `api_only`）はRails 5.0で標準化されました。以降のバージョンで利用でき、本記事は執筆時点の最新安定版であるRails 8.1系を前提にしています。

### JSONの整形にはどのライブラリがおすすめですか？

属性が少なければ標準の `as_json` で十分です。本格的な整形が必要になったら、開発が活発で高速な alba が有力候補です。`active_model_serializers` はメンテナンスモードのため、新規採用は避けるのが無難です。

## 関連記事

- [Railsジェネレータ（rails generate）の使い方｜モデル・scaffold・カスタム生成まで](https://www.issoh.co.jp/tech/details/2874/)
- [docker-composeとは？複数コンテナをymlで定義し一括管理する仕組みを解説](https://www.issoh.co.jp/tech/details/13282/)
- [ruby on rails を vscode で開発する環境構築【2026年版】拡張機能・デバッグ・Dev Container](https://www.issoh.co.jp/tech/details/2878/)
- [CSRF（クロスサイトリクエストフォージェリ）とは何か？概要とそのリスクについて解説](https://www.issoh.co.jp/column/details/3984/)
- [Sidekiqとは？Rubyで非同期処理を簡単に実現するバックグラウンドジョブツール](https://www.issoh.co.jp/tech/details/7843/)

---

出典: [Rails APIとは？作成手順・JWT認証・React連携・Docker環境を実装解説【Rails 8.1】](<https://www.issoh.co.jp/tech/details/2905/>)（株式会社一創）
