Rails
A Ruby on Rails integration gem for LightRate API throttling. This gem provides seamless integration with the LightRate API using controller before_actions to automatically throttle requests using local token buckets that automatically refill from the server when needed.
Features
- Controller-Level Throttling: Use
throttle_with_lightratein any controller to enable automatic rate limiting - Flexible User Identification: Customize user identification per-controller with full access to controller context
- Local Token Bucket Only: Uses only the local token bucket approach for efficient throttling with automatic server refills
- Custom Exception Handling: Raises
LightRateNoTokensAvailablewhen no tokens are available - Fine-Grained Control: Use
:onlyor:exceptoptions to throttle specific actions - Controller Helpers: Manual token consumption methods for advanced use cases
Installation
Add this line to your application’s Gemfile:
gem 'lightrate-rails'And then execute:
bundle installOr install it yourself as:
gem install lightrate-railsConfiguration
Basic Setup
Required: Configure Lightrate in your Rails application initializer:
# config/initializers/lightrate_rails.rb
LightrateRails.configure do |config|
# Required: Your LightRate API key
config.api_key = ENV['LIGHTRATE_API_KEY']
# Required: Your LightRate Application ID
config.application_id = ENV['LIGHTRATE_APPLICATION_ID']
# Optional: Enable/disable throttling globally (default: true)
config.enabled = Rails.env.production?
# Optional: Default bucket size (default: 5)
config.default_local_bucket_size = 10
endNote: You must provide both a valid API key and Application ID. The gem will raise a ConfigurationError if either is missing.
Advanced Configuration
LightrateRails.configure do |config|
# Required: Your LightRate API key
config.api_key = ENV['LIGHTRATE_API_KEY']
# Required: Your LightRate Application ID
config.application_id = ENV['LIGHTRATE_APPLICATION_ID']
# Enable/disable throttling globally (default: true)
config.enabled = true
# Default local bucket size (default: 5)
config.default_local_bucket_size = 10
# API client configuration
config.timeout = 30
config.retry_attempts = 3
config.logger = Rails.logger
endUsage
Global Client Architecture
The gem creates a single global LightRate client instance during Rails initialization. This approach provides several benefits:
- Efficiency: No client creation overhead on each request
- Shared Token Buckets: Token buckets are shared across all requests, providing better rate limiting
- Memory Efficiency: Single client instance reduces memory usage
- Consistent State: All parts of your application use the same client configuration
Controller-Level Throttling
The gem automatically includes LightrateRails::ControllerHelper in all your controllers. To enable throttling, simply call throttle_with_lightrate in any controller:
Basic Usage
# Throttle all actions in this controller
class ApiController < ApplicationController
throttle_with_lightrate
end
# Only throttle specific actions
class UsersController < ApplicationController
throttle_with_lightrate only: [:create, :update, :destroy]
def index; end # NOT throttled
def show; end # NOT throttled
def create; end # Throttled
def update; end # Throttled
def destroy; end # Throttled
end
# Throttle all actions EXCEPT specific ones
class PostsController < ApplicationController
throttle_with_lightrate except: [:index, :show]
def index; end # NOT throttled
def show; end # NOT throttled
def create; end # Throttled
def update; end # Throttled
def destroy; end # Throttled
end
# Disable throttling for this entire controller
class HealthController < ApplicationController
skip_lightrate_throttling
def status; end # NOT throttled
def ping; end # NOT throttled
endCustom User Identification
By default, the gem uses current_user.id to identify users. You can customize this per-controller:
# Use a different method on your user object
class ApiController < ApplicationController
throttle_with_lightrate user_identifier: -> { current_user&.uuid }
end
# Use a symbol for a controller method
class ApiController < ApplicationController
throttle_with_lightrate user_identifier: :get_api_user_id
private
def get_api_user_id
request.headers['X-API-User-ID']
end
end
# Combine multiple identifiers
class ApiController < ApplicationController
throttle_with_lightrate user_identifier: -> {
"#{current_user&.id}:#{current_organization&.id}"
}
end
# Use API token for identification
class ApiV2Controller < ApplicationController
throttle_with_lightrate user_identifier: -> {
current_api_user&.token
}
end
# Use IP address for public endpoints
class PublicApiController < ApplicationController
throttle_with_lightrate user_identifier: -> {
request.remote_ip
}
end
# Combine with :only option
class ComplexController < ApplicationController
throttle_with_lightrate(
only: [:create, :update],
user_identifier: -> { request.headers['X-User-Token'] }
)
endManual Token Management in Controllers
For advanced use cases, you can manually manage token consumption. The helper methods are automatically available in all controllers:
class ApiController < ApplicationController
def path_specific_operation
# Manually consume a token for a specific path
consume_lightrate_token_for_path(path: '/api/v1/special')
# Your operation here
end
def current_path_operation
# Consume a token for the current request path (most common use case)
consume_lightrate_token_for_current_path
# Your operation here
end
def custom_user_operation
# Use a different user identifier
consume_lightrate_token_for_current_path(
user_identifier: current_user.uuid
)
# Your operation here
end
def specific_path_operation
# Consume token for a specific path and method
consume_lightrate_token_for_path(
path: "/api/v1/special-endpoint",
method: "POST",
user_identifier: current_user.id
)
# Your operation here
end
endController Configuration Methods
Configure throttling behavior at the controller level:
| Method | Description | Options |
|---|---|---|
throttle_with_lightrate(options = {}) | Enable throttling for this controller | only: - Array of action names to throttleexcept: - Array of action names to excludeuser_identifier: - Proc or Symbol for custom user identification |
skip_lightrate_throttling | Disable throttling for this entire controller | None |
Available Helper Methods
The gem provides several helper methods for manual token management:
| Method | Description | Parameters |
|---|---|---|
consume_lightrate_token_for_current_path | Consume token for current request path | user_identifier |
consume_lightrate_token_for_path | Consume token for specific path | path, method, user_identifier |
Most Common Use Cases:
consume_lightrate_token_for_current_path- Use this when you want to consume a token for the current request pathconsume_lightrate_token_for_path- Use this for specific paths different from the current request
Exception Handling
The gem automatically handles rate limiting through controller callbacks:
- HTML requests: Redirects with flash message
- JSON requests: Returns 429 status with JSON error
- XML requests: Returns 429 status with XML error
Customizing Throttling Responses
You can customize the throttling response by overriding the handle_rate_limit_exceeded method in your controllers:
class ApiController < ApplicationController
throttle_with_lightrate
private
def handle_rate_limit_exceeded(exception)
# Custom throttling response
render json: {
error: 'Rate Limited',
message: 'You have exceeded the rate limit for this endpoint.',
path: exception.path,
user: exception.user_identifier,
retry_after: 30
}, status: 429
end
endException Classes
LightRateNoTokensAvailable
Raised when no tokens are available for a request.
begin
consume_lightrate_tokens(operation: 'my_operation')
rescue LightrateRails::LightRateNoTokensAvailable => e
puts "No tokens available for path: #{e.path}"
puts "User: #{e.user_identifier}"
puts "Response: #{e.response}"
endConfiguration Options
| Option | Type | Default | Description |
|---|---|---|---|
api_key | String | nil | Required - Your LightRate API key |
application_id | String | nil | Required - Your LightRate Application ID |
enabled | Boolean | true | Enable/disable throttling globally |
default_local_bucket_size | Integer | 5 | Default size for local token buckets |
timeout | Integer | 30 | API request timeout in seconds |
retry_attempts | Integer | 3 | Number of API retry attempts |
logger | Logger | Rails.logger | Logger for API requests |