Skip to content
Learni
View all tutorials
Développement Backend

How to Create a REST API with Ruby on Rails in 2026

18 minINTERMEDIATE
Lire en français

Introduction

Ruby on Rails remains a leading framework in 2026 for rapidly building high-performance REST APIs. This intermediate tutorial guides you through creating a complete task management API. You will learn how to structure Active Record models, expose secure JSON endpoints, and implement robust tests. The focus is on modern best practices: JSON:API serialization, server-side validation, and standardized error handling. This guide targets developers with existing Rails experience who want to reach a professional level.

Prerequisites

  • Ruby 3.3+ and Rails 8.0+
  • Basic knowledge of Active Record and MVC
  • PostgreSQL installed
  • Testing tool such as RSpec or Minitest

Project Initialization

terminal
rails new task_api --api -d postgresql
cd task_api
rails db:create

The --api flag generates a lightweight structure without views. PostgreSQL is used for its reliability with Rails migrations. Run this command in a clean terminal.

Task Model Creation

app/models/task.rb
class Task < ApplicationRecord
  validates :title, presence: true, length: { minimum: 3 }
  validates :status, inclusion: { in: %w[todo in_progress done] }
  enum :status, { todo: 0, in_progress: 1, done: 2 }
end

The model includes strict validations and an enum for status. This ensures data integrity at the model layer before reaching the controller.

Associated Migration

db/migrate/20260115120000_create_tasks.rb
class CreateTasks < ActiveRecord::Migration[8.0]
  def change
    create_table :tasks do |t|
      t.string :title, null: false
      t.text :description
      t.integer :status, default: 0, null: false
      t.timestamps
    end
    add_index :tasks, :status
  end
end

The migration creates the table with an index on status to optimize filtering queries. Run rails db:migrate afterward.

Tasks Controller

app/controllers/tasks_controller.rb
class TasksController < ApplicationController
  before_action :set_task, only: [:show, :update, :destroy]

  def index
    @tasks = Task.all
    render json: @tasks
  end

  def show
    render json: @task
  end

  def create
    @task = Task.new(task_params)
    if @task.save
      render json: @task, status: :created
    else
      render json: { errors: @task.errors }, status: :unprocessable_entity
    end
  end

  private

  def set_task
    @task = Task.find(params[:id])
  end

  def task_params
    params.require(:task).permit(:title, :description, :status)
  end
end

The controller handles standard CRUD operations with appropriate HTTP error handling. before_action factors out record lookup.

Route Configuration

config/routes.rb
Rails.application.routes.draw do
  resources :tasks, only: [:index, :show, :create, :update, :destroy]
end

RESTful routes are limited to required actions. This exposes only the necessary API endpoints without extra routes.

Tests with Minitest

test/controllers/tasks_controller_test.rb
require 'test_helper'

class TasksControllerTest < ActionDispatch::IntegrationTest
  test 'should get index' do
    get tasks_url
    assert_response :success
    assert_not_nil JSON.parse(response.body)
  end

  test 'should create task' do
    assert_difference('Task.count') do
      post tasks_url, params: { task: { title: 'Test task', status: 'todo' } }
    end
    assert_response :created
  end
end

The tests cover the main endpoints and validate status codes. Run rails test to verify everything works correctly.

Best Practices

  • Always use validations in models
  • Limit parameters with strong parameters
  • Return semantic HTTP status codes (201, 422, 404)
  • Version the API as early as possible (/api/v1)
  • Add pagination for large collections

Common Errors to Avoid

  • Forgetting model validations and allowing invalid data
  • Exposing sensitive attributes without a serializer
  • Not handling ActiveRecord::RecordNotFound exceptions
  • Ignoring integration tests for endpoints

Going Further

Explore advanced serialization with fast_jsonapi or jsonapi-serializer. Check out our advanced Rails courses.