RESTful API design with Rails

Sarah Mitchell Feb 2026
4 tabs
module Api
  module V1
    class UsersController < ApplicationController
      before_action :authenticate_user!, except: [:index, :show]
      before_action :set_user, only: [:show, :update, :destroy]

      # GET /api/v1/users
      def index
        @users = User.page(params[:page]).per(params[:per_page] || 20)

        render json: {
          users: @users.map { |user| UserSerializer.new(user).as_json },
          meta: pagination_meta(@users)
        }
      end

      # GET /api/v1/users/:id
      def show
        render json: UserSerializer.new(@user), status: :ok
      end

      # POST /api/v1/users
      def create
        @user = User.new(user_params)

        if @user.save
          render json: UserSerializer.new(@user), status: :created
        else
          render json: { errors: @user.errors.full_messages }, status: :unprocessable_entity
        end
      end

      # PATCH/PUT /api/v1/users/:id
      def update
        if @user.update(user_params)
          render json: UserSerializer.new(@user), status: :ok
        else
          render json: { errors: @user.errors.full_messages }, status: :unprocessable_entity
        end
      end

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

      private

      def set_user
        @user = User.find(params[:id])
      rescue ActiveRecord::RecordNotFound
        render json: { error: 'User not found' }, status: :not_found
      end

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

      def pagination_meta(collection)
        {
          current_page: collection.current_page,
          total_pages: collection.total_pages,
          total_count: collection.total_count,
          per_page: collection.limit_value
        }
      end
    end
  end
end
4 files · ruby Explain with highlit

Rails conventions support RESTful API development. I use resourceful routing for standard CRUD operations. Controllers inherit from ActionController::API for API-only apps. JSON serialization with Jbuilder or Active Model Serializers structures responses. Versioning uses namespaces—/api/v1/users. Authentication with JWT tokens or OAuth. Pagination with kaminari or pagy gems. Rate limiting protects endpoints. CORS configuration allows cross-origin requests. Error handling returns appropriate HTTP status codes. API documentation with rswag or Swagger. Filtering, sorting, and searching enhance usability. Proper REST design creates intuitive, maintainable APIs. Following conventions reduces decisions and improves consistency.