Rails API Mode — Building RESTful JSON APIs
In this tutorial, you will learn about Rails API Mode. We cover key concepts, practical examples, and best practices to help you master this topic.
Rails API mode strips unnecessary middleware for JSON-only applications, supporting versioning, serializers, CORS, rate limiting, error handling, and JSON API conventions.
What You'll Learn
By the end of this tutorial, you'll create an API-only Rails app, implement serializers, handle request validation, add CORS and rate limiting, version endpoints, and format JSON responses.
Why API Mode Matters
API mode removes session management, cookie handling, and view rendering for better performance. It focuses on request Parsing and JSON response generation.
Real-World Use
A mobile app backend uses Rails API with JSON API serializers, token authentication, rate limiting with Rack::Attack, and CORS for the web client.
API Path
flowchart LR
A[Rails] --> B[API Mode]
B --> C[Serializers]
B --> D[Versioning]
B --> E[CORS]
B --> F[Error Handling]
B --> G{You Are Here}
style G fill:#f90,color:#fff
Creating an API App
Generate a new API-only Rails application.
rails new my_api --api
# config/application.rb
config.api_only = true
# Removes: views, cookies, session, flash, CSRF protection
# Keeps: JSON/XML rendering, HTTP caching, etags
API Versioning
Version your API routes.
# config/routes.rb
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
resources :products
resources :categories, only: [:index, :show]
end
namespace :v2 do
resources :products
end
end
end
# app/controllers/api/base_controller.rb
module Api
class BaseController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :not_found
rescue_from ActiveRecord::RecordInvalid, with: :unprocessable_entity
private
def not_found
render json: { error: "Resource not found" }, status: :not_found
end
def unprocessable_entity(exception)
render json: { errors: exception.record.errors.full_messages }, status: :unprocessable_entity
end
end
end
Serializers
Transform models to JSON.
# Gemfile
gem "jsonapi-serializer"
# app/serializers/product_serializer.rb
class ProductSerializer
include JSONAPI::Serializer
attributes :name, :price, :description, :published
attribute :formatted_price do |product|
number_to_currency(product.price)
end
attribute :created_at do |product|
product.created_at.iso8601
end
belongs_to :category
has_many :reviews
end
# Controller
class Api::V1::ProductsController < Api::BaseController
def index
products = Product.includes(:category).published
render json: ProductSerializer.new(products, {
params: { current_user: current_user },
include: [:category],
}).serializable_hash
end
end
Rate Limiting
Protect API with rate limiting.
# Gemfile
gem "rack-attack"
# config/initializers/rack_attack.rb
class Rack::Attack
limit = 100
period = 1.minute
throttle("api/ip", limit: limit, period: period) do |req|
if req.path.start_with?("/api/")
req.ip
end
end
throttle("api/user", limit: 1000, period: 1.hour) do |req|
if req.path.start_with?("/api/")
req.env["HTTP_AUTHORIZATION"]
end
end
self.throttled_responder = lambda do |env|
headers = { "Retry-After" => period.to_s }
[429, headers, [{ error: "Rate limit exceeded" }.to_json]]
end
end
Common Mistakes
1. Using API Mode for Full-Stack Apps
API mode disables features needed for server-rendered HTML. Use full Rails for HTML apps.
2. Not Versioning APIs
API changes break clients. Version from the start, even for v1.
3. Exposing Internal Errors
Never include stack traces in API responses. Use rescue_from for consistent errors.
4. Skipping Request Validation
API requests need strong parameter validation like web forms.
5. Not Setting Proper HTTP Status Codes
Return 201 for created, 422 for validation errors, 401 for unauthorized, 403 for forbidden.
Practice Questions
1. What does config.api_only = true do?
Removes middleware for sessions, cookies, views, and CSRF protection.
2. Why should you version APIs?
To avoid breaking existing clients when the API changes.
3. What is a serializer for?
Transforming model data into JSON format suitable for API responses.
4. How do you rate limit API requests?
Use rack-attack gem with throttle rules based on IP or user token.
5. Challenge: Create an API endpoint with Serialization and error handling.
module Api
module V1
class ProductsController < BaseController
before_action :authenticate
def index
products = Product.published.includes(:category)
render json: ProductSerializer.new(products, include: [:category])
end
def show
product = Product.find(params[:id])
render json: ProductSerializer.new(product)
end
def create
product = current_user.products.new(product_params)
product.save!
render json: ProductSerializer.new(product), status: :created
end
end
end
end
FAQ
Mini Project: Products API
Build a complete products API with versioning.
# config/routes.rb
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
resources :products, only: [:index, :show, :create, :update]
get "search/products", to: "products#search"
end
end
end
What's Next
Rails Serializers Rails Testing RSpec Rails Factory Bot
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro