Building APIs with Rails API Mode
Rails API Mode is a way to generate a Rails application that’s optimized for building APIs. It strips away the unnecessary components of a full Rails application — like views, helpers, and asset pipelines — leaving you with a lean, focused API backend.
What Is Rails API Mode?
When you create a new Rails app with --api, you get a slimmed-down version that includes only what you need for an API:
- Controllers that respond to JSON requests
- Models for database interactions
- Routing for RESTful endpoints
- Middleware tailored for API requests (no sessions, cookies, or browser-specific stuff)
The key difference from a full Rails app is what’s excluded:
| Full Rails App | API Mode |
|---|---|
| ActionView | Excluded |
| ActionMailer | Excluded |
| Asset Pipeline | Excluded |
| Session Middleware | Excluded |
| Cookies | Excluded |
| Flash messages | Excluded |
This means faster boot times, smaller memory footprint, and a more focused codebase.
Creating an API-Only App
Generate a new API-only Rails application:
rails new my_api --api
This creates an app with the API-focused stack. You can verify it by checking config/application.rb:
module MyApi
class Application < Rails::Application
config.api_only = true
end
end
Converting an Existing App
If you have a full Rails app and want to convert it to API mode, you can do that too.
Step 1: Set API Mode in Config
In config/application.rb:
config.api_only = true
Step 2: Use API Controllers
Instead of ActionController::Base, use ActionController::API as your base class:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::API
end
ActionController::API is a lighter weight controller that includes only the essentials for handling requests — no view rendering, no session management, no cookies.
Step 3: Remove Unnecessary Middleware
In config/application.rb, you can remove middleware you don’t need:
module MyApp
class Application < Rails::Application
config.api_only = true
# Remove these if not using:
config.middleware.delete ActionDispatch::Cookies
config.middleware.delete ActionDispatch::Session::CookieStore
config.middleware.delete ActionDispatch::Flash
end
end
Building Your First API Endpoint
Let’s create a simple RESTful resource. Say we want an API for managing users.
Generate a Resource
rails generate scaffold User name:string email:string
This creates the model, controller, and routes. The controller will respond to JSON by default.
Check the Routes
rails routes
You’ll see standard RESTful routes:
users GET /users(.:format) users#index
users POST /users(.:format) users#create
user GET /users/:id(.:format) users#show
user PATCH /users/:id(.:format) users#update
user PUT /users/:id(.:format) users#update
user DELETE /users/:id(.:format) users#destroy
Test the API
Start the server and make a request:
rails server -p 3000
# Create a user
curl -X POST http://localhost:3000/users \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "email": "alice@example.com"}'
# List users
curl http://localhost:3000/users
# Get a specific user
curl http://localhost:3000/users/1
The responses will be JSON automatically.
Customizing JSON Rendering
Using Jbuilder
Rails includes Jbuilder for building complex JSON responses. Create a view file:
# app/views/users/show.json.jbuilder
json.id @user.id
json.name @user.name
json.email @user.email
json.created_at @user.created_at.iso8601
Using Active Model Serializers
For more control, add the active_model_serializers gem:
gem 'active_model_serializers'
Generate a serializer:
rails generate serializer User
# app/serializers/user_serializer.rb
class UserSerializer < ActiveModel::Serializer
attributes :id, :name, :email, :created_at
def created_at
object.created_at.iso8601
end
end
In your controller, rendering automatically uses the serializer:
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
render json: @user
end
end
Authentication
APIs typically need authentication. Here are common approaches:
Token Authentication
Implement a simple token-based auth:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::API
before_action :authenticate_request
private
def authenticate_request
token = request.headers['Authorization']&.split(' ')&.last
@current_user = User.find_by(api_token: token)
render json: { error: 'Unauthorized' }, status: :unauthorized unless @current_user
end
end
Using Devise Token Auth
For production apps, use a gem like devise_token_auth:
gem 'devise_token_auth'
This provides full token-based authentication out of the box.
Error Handling
API mode still supports standard Rails error handling, but you might want custom JSON error responses:
# app/controllers/application_controller.rb
rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
rescue_from ActiveRecord::RecordInvalid, with: :render_validation_error
private
def render_not_found(exception)
render json: { error: exception.message }, status: :not_found
end
def render_validation_error(exception)
render json: { errors: exception.record.errors.full_messages }, status: :unprocessable_entity
end
CORS Configuration
If your API will be accessed from browsers on different domains, configure CORS:
# Gemfile
gem 'rack-cors'
# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'http://localhost:3001' # Your frontend domain
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options]
end
end
Versioning Your API
As your API evolves, you’ll want version it. A common approach:
# config/routes.rb
namespace :api do
namespace :v1 do
resources :users
end
end
This creates routes like /api/v1/users.
Organize your controllers:
# app/controllers/api/v1/users_controller.rb
module Api
module V1
class UsersController < ApplicationController
# Your logic here
end
end
end
When to Use API Mode
Rails API Mode is ideal when:
- Building a JSON API for a JavaScript frontend (React, Vue, etc.)
- Creating a mobile app backend
- Providing an API for third-party integrations
- Microservices that don’t need views
Stick with full Rails when:
- You need server-side rendering (SSR)
- You want the asset pipeline
- You’re building a traditional web app
See Also
- Rails Middleware — Understanding the request processing pipeline
- ActiveJob and Sidekiq — Background job processing
- Rails Routing — RESTful route design