If you don’t limit your API usage, bad users can DDOS your server.

If you don’t track API usage, how do you know if it is even used?

Apps like Twitter and Shopify have daily or monthly (30-day) API usage limits:

In this tutorial we will track API usage per user and add a 30-day max limit of API requests per user.

Example of API request being blocked by status 429 Too Many Requests:


ApiRequest model will store the usage data:

rails g model ApiRequest user:references path method

On the user model:

  • set a max limit of requests per month
  • count requests within the last 30 days
  • check if the limit is exceeded
# app/models/user.rb
class User < ApplicationRecord

  has_many :api_requests


  def api_requests_within_last_30_days
    api_requests.where("created_at > ?", 30.days.ago).count

  def api_request_limit_exceeded?
    api_requests_within_last_30_days >= MAX_API_REQUESTS_PER_30_DAYS

In the base API controller, log API requests with log_api_request and check limit:

# app/controllers/api/v1/authenticated_controller.rb
  before_action :check_api_limit
  before_action :log_api_request




  def log_api_request
    current_user.api_requests.create!(path: request.path, method: request.method)
    # in the response header, include remaining api request count
    response.headers['X-Superails-User-Api-Call-Limit'] = "#{current_user.api_requests_within_last_30_days.to_s}/#{User::MAX_API_REQUESTS_PER_30_DAYS.to_s}"

  def check_api_limit
    if current_user.api_request_limit_exceeded?
      render json: { message: "API request limit exceeded" }, status: :too_many_requests

Now when a user tries to make an API request, we will first check if the user has exceeded the limit.

If the limit is not exceeded, the request is performed and data about it is stored in the ApiRequest model.

Shopify also includes a Rate limits header. With response.headers['X-Superails-User-Api-Call-Limit'] we are doing the same!

To display request headers in a response from a curl request, you can include the -v option: curl -v -X GET localhost:3000/api/v1/home/index.json -H "Authorization: Bearer MySecretToken".


That’s it!