Back to Tutorials

Building REST APIs with Ruby on Rails

Why Rails for APIs?

Ruby on Rails provides convention over configuration, making it easy to build RESTful APIs quickly with built-in best practices.

Creating a Rails API

# Create new Rails API
rails new my_api --api

# Generate scaffold
rails generate scaffold User name:string email:string

# Run migrations
rails db:migrate

# Start server
rails server

API Controller

# app/controllers/api/v1/users_controller.rb
class Api::V1::UsersController < ApplicationController
  before_action :set_user, only: [:show, :update, :destroy]

  # GET /api/v1/users
  def index
    @users = User.all
    render json: @users
  end

  # GET /api/v1/users/1
  def show
    render json: @user
  end

  # POST /api/v1/users
  def create
    @user = User.new(user_params)
    
    if @user.save
      render json: @user, status: :created
    else
      render json: @user.errors, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /api/v1/users/1
  def update
    if @user.update(user_params)
      render json: @user
    else
      render json: @user.errors, status: :unprocessable_entity
    end
  end

  # DELETE /api/v1/users/1
  def destroy
    @user.destroy
    head :no_content
  end

  private

  def set_user
    @user = User.find(params[:id])
  end

  def user_params
    params.require(:user).permit(:name, :email)
  end
end

Routes Configuration

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

Serializers

# app/serializers/user_serializer.rb
class UserSerializer
  include FastJsonapi::ObjectSerializer
  
  attributes :id, :name, :email, :created_at
  
  has_many :posts
end

# In controller
def index
  @users = User.all
  render json: UserSerializer.new(@users).serializable_hash
end

Authentication with JWT

# app/controllers/api/v1/auth_controller.rb
class Api::V1::AuthController < ApplicationController
  def login
    @user = User.find_by(email: params[:email])
    
    if @user && @user.authenticate(params[:password])
      token = JWT.encode({ user_id: @user.id }, Rails.application.secret_key_base)
      render json: { token: token, user: @user }
    else
      render json: { error: "Invalid credentials" }, status: :unauthorized
    end
  end
end

Best Practices

  • Use API versioning
  • Use serializers for JSON responses
  • Implement pagination
  • Use strong parameters
  • Handle errors gracefully