### Manual Installation Dependencies Source: https://hexdocs.pm/ash_rate_limiter/index.html Add the dependency to mix.exs and configure the formatter in .formatter.exs. ```elixir def deps do [ {:ash_rate_limiter, "~> 2.0.0"} ] end ``` ```elixir [ import_deps: [:ash, :ash_rate_limiter], # ... other formatter config ] ``` -------------------------------- ### Install AshRateLimiter via Igniter Source: https://hexdocs.pm/ash_rate_limiter/index.html Recommended method for adding the dependency and configuring the formatter. ```elixir mix igniter.install ash_rate_limiter ``` -------------------------------- ### Basic Rate Limiting Patterns Source: https://hexdocs.pm/ash_rate_limiter/index.html Examples of simple, per-user, and multi-action rate limiting configurations. ```elixir rate_limit do backend MyApp.Hammer action :create, limit: 5, per: :timer.minutes(1) end ``` ```elixir rate_limit do backend MyApp.Hammer action :create, limit: 10, per: :timer.minutes(5), key: fn changeset, context -> "user:#{context.actor.id}:create" end end ``` ```elixir rate_limit do backend MyApp.Hammer action :create, limit: 10, per: :timer.minutes(5) action :update, limit: 20, per: :timer.minutes(5) action :read, limit: 100, per: :timer.minutes(1) end ``` -------------------------------- ### Generate bucket keys for actions Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.html Examples demonstrating how to generate bucket keys for various Ash actions, including handling of primary keys, actors, and tenants. ```elixir iex> Example.Post ...> |> Ash.Changeset.for_create(:create, post_attrs()) ...> |> key_for_action(%{}) "example/post/create" iex> Example.Post ...> |> Ash.Query.for_read(:read) ...> |> key_for_action(%{}) "example/post/read" iex> generate_post(id: "0196ebc0-83b4-7938-bc9d-22ae65dbec0b") ...> |> Ash.Changeset.for_update(:update, %{title: "Local Farmer Claims 'Space Zombie' Wrecked His Barn"}) ...> |> key_for_action(%{}) "example/post/update?id=0196ebc0-83b4-7938-bc9d-22ae65dbec0b" iex> generate_post(id: "0196ebc6-4839-7a9e-b2a6-feb0eabc8772") ...> |> Ash.Changeset.for_destroy(:destroy) ...> |> key_for_action(%{}) "example/post/destroy?id=0196ebc6-4839-7a9e-b2a6-feb0eabc8772" iex> generate_post(id: "0196ebcd-fabf-74c3-9585-8b13c5f07068") ...> |> Ash.Changeset.for_destroy(:destroy) ...> |> key_for_action(%{}, include_pk?: false) "example/post/destroy" iex> Example.Post ...> |> Ash.Changeset.for_create(:create, post_attrs()) ...> |> key_for_action(%{actor: %{role: :time_traveller}}, include_actor_attributes: [:role]) "example/post/create?actor%5Brole%5D=time_traveller" iex> Example.Post ...> |> Ash.Changeset.new() ...> |> Ash.Changeset.set_tenant("Hill Valley Telegraph") ...> |> Ash.Changeset.for_create(:create, post_attrs()) ...> |> key_for_action(%{}, include_tenant?: true) "example/post/create?tenant=Hill%20Valley%20Telegraph" ``` -------------------------------- ### Custom Key Function Examples Source: https://hexdocs.pm/ash_rate_limiter/index.html Define how requests are grouped for rate limiting using key functions. ```elixir # Rate limit per IP address key: fn _changeset, context -> "ip:#{context[:ip_address]}" end # Rate limit per user and action key: fn changeset, context -> "user:#{context.actor.id}:action:#{changeset.action.name}" end # Use the built-in key function with options key: {&AshRateLimiter.key_for_action/2, include_actor_attributes: [:role]} ``` -------------------------------- ### Configure Rate Limiting for Actions Source: https://hexdocs.pm/ash_rate_limiter/dsl-ashratelimiter.html Example of defining a rate limit block within an Ash resource, specifying the backend and action-specific limits. ```elixir rate_limit do backend MyApp.RateLimiter action :create, limit: 10, per: :timer.minutes(5) end ``` -------------------------------- ### Configure Hammer Backend and Supervision Source: https://hexdocs.pm/ash_rate_limiter/index.html Create a Hammer module and add it to the application supervision tree. ```elixir # lib/my_app/hammer.ex defmodule MyApp.Hammer do use Hammer, backend: :ets end ``` ```elixir # lib/my_app/application.ex @impl true def start(_type, _args) do children = [ # ... # Add the line below: {MyApp.Hammer, clean_period: :timer.minutes(1)}, # ... ] opts = [strategy: :one_for_one, name: MyApp.Supervisor] Supervisor.start_link(children, opts) end ``` ```elixir # config/config.exs config :my_app, :ash_rate_limiter, hammer: MyApp.Hammer ``` -------------------------------- ### Implement AshRateLimiter.Backend Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.Backend.html Create a custom module that implements the AshRateLimiter.Backend behaviour to define rate limiting logic. ```elixir defmodule MyApp.RateLimiter do @behaviour AshRateLimiter.Backend @impl true def hit(key, window_ms, limit) do # Your rate limiting logic here {:allow, 1} end end ``` -------------------------------- ### key_for_action(query_or_changeset, context, opts \ []) Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.html Generates a bucket key for rate limiting based on the domain, resource, and action names. It supports including primary keys, actor attributes, and tenant information in the generated key. ```APIDOC ## key_for_action(query_or_changeset, context, opts \ []) ### Description The default bucket key generation function for AshRateLimiter. It generates a key based on the domain, resource, and action names, optionally including primary keys for update and destroy actions. ### Parameters - **query_or_changeset** (Ash.Query.t | Ash.Changeset.t | Ash.ActionInput.t) - Required - The query, changeset, or action input to generate a key for. - **context** (map) - Required - The context map. - **opts** (keyword) - Optional - Configuration options. #### Options - **:include_pk?** (boolean) - Optional - Whether to include primary keys in the generated key for update/destroy actions. Default: true. - **:include_actor_attributes** (list of atom) - Optional - A list of attributes to include from the current actor. Default: []. - **:include_tenant?** (boolean) - Optional - Whether to include the tenant in the bucket key. Default: false. ### Returns - **String.t** - The generated bucket key string. ``` -------------------------------- ### Retrieve rate limit backend module (bang version) Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.Info.html Fetches the configured rate limiting backend module, raising an error if not found. ```elixir @spec rate_limit_backend!(dsl_or_extended :: module() | map()) :: module() | no_return() ``` -------------------------------- ### rate_limit_backend!(dsl_or_extended) Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.Info.html Retrieves the configured rate limiting backend module, raising an error if not found. ```APIDOC ## rate_limit_backend!(dsl_or_extended) ### Description Retrieves the configured rate limiting backend module. Raises an error if the backend is not configured. ### Signature `rate_limit_backend!(dsl_or_extended :: module() | map()) :: module() | no_return()` ``` -------------------------------- ### Retrieve rate limit DSL options Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.Info.html Returns a map of configured or default rate limit options. ```elixir @spec rate_limit_options(dsl_or_extended :: module() | map()) :: %{ required(atom()) => any() } ``` -------------------------------- ### Define key_for_action specification Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.html Specifies the signature for the default bucket key generation function. ```elixir @spec key_for_action( Ash.Query.t() | Ash.Changeset.t() | Ash.ActionInput.t(), map(), keyword() ) :: String.t() ``` -------------------------------- ### Retrieve rate limit backend module Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.Info.html Fetches the configured rate limiting backend module, returning an error tuple if not found. ```elixir @spec rate_limit_backend(dsl_or_extended :: module() | map()) :: {:ok, module()} | :error ``` -------------------------------- ### rate_limit(options) Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.BuiltinPreparations.html Adds a rate-limit change directly to an Ash action. This function returns a tuple containing the preparation module and the provided options. ```APIDOC ## rate_limit(options) ### Description Adds a rate-limit change directly to an action. ### Signature `rate_limit(rate_limit_options()) :: {AshRateLimiter.Preparation, rate_limit_options()}` ### Parameters - **options** (rate_limit_options) - Required - A keyword list containing the following keys: - **limit** (pos_integer) - Required - The maximum number of events allowed within the given scale. - **per** (pos_integer) - Required - The time period (in milliseconds) for which events are counted. - **key** (String.t | AshRateLimiter.keyfun) - Optional - The key used to identify the event. Defaults to `&AshRateLimiter.key_for_action/2`. - **on** (:before_action | :before_transaction) - Optional - The lifecycle hook to use. Defaults to `:before_action`. ``` -------------------------------- ### hit(key, window_ms, limit) Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.Backend.html The hit/3 callback is used to perform rate limiting logic. It takes a key, a time window in milliseconds, and a limit, returning either an :allow or :deny tuple with the current count. ```APIDOC ## hit(key, window_ms, limit) ### Description Performs the rate limiting check for a given key within a specified time window. ### Signature `hit(key :: String.t(), window_ms :: pos_integer(), limit :: pos_integer()) :: {:allow, pos_integer()} | {:deny, pos_integer()}` ### Parameters - **key** (String.t) - The identifier for the rate limit bucket. - **window_ms** (pos_integer) - The time window in milliseconds. - **limit** (pos_integer) - The maximum number of hits allowed in the window. ### Returns - **{:allow, pos_integer()}** - Returned when the request is within the limit, including the current count. - **{:deny, pos_integer()}** - Returned when the request exceeds the limit, including the current count. ``` -------------------------------- ### Configure Action-Specific Rate Limit Source: https://hexdocs.pm/ash_rate_limiter/dsl-ashratelimiter.html Syntax for defining a rate limit for a specific action within the DSL. ```elixir action action ``` -------------------------------- ### rate_limit_backend(dsl_or_extended) Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.Info.html Retrieves the configured rate limiting backend module. ```APIDOC ## rate_limit_backend(dsl_or_extended) ### Description Retrieves the configured rate limiting backend module. Returns {:ok, module()} on success or :error if not found. ### Signature `rate_limit_backend(dsl_or_extended :: module() | map()) :: {:ok, module()} | :error` ``` -------------------------------- ### Manual Action Integration Source: https://hexdocs.pm/ash_rate_limiter/index.html Apply rate limiting directly to specific actions using changes or preparations. ```elixir defmodule MyApp.Post do use Ash.Resource, domain: MyApp actions do create :create do change {AshRateLimiter.Change, limit: 10, per: :timer.minutes(5)} end read :read do prepare {AshRateLimiter.Preparation, limit: 100, per: :timer.minutes(1)} end end end ``` -------------------------------- ### rate_limit_options(dsl_or_extended) Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.Info.html Retrieves the configured rate limit DSL options as a map. ```APIDOC ## rate_limit_options(dsl_or_extended) ### Description Returns a map containing the configured or default rate limit options. ### Signature `rate_limit_options(dsl_or_extended :: module() | map()) :: %{required(atom()) => any()}` ``` -------------------------------- ### Add Rate Limiting to Ash Resource Source: https://hexdocs.pm/ash_rate_limiter/index.html Use the rate_limit DSL section to define limits for specific actions. ```elixir defmodule MyApp.Post do use Ash.Resource, domain: MyApp, extensions: [AshRateLimiter] rate_limit do # Configure hammer backend backend MyApp.Hammer # Limit create action to 10 requests per 5 minutes action :create, limit: 10, per: :timer.minutes(5) # Limit read action to 100 requests per minute action :read, limit: 100, per: :timer.minutes(1) end # ... rest of your resource definition end ``` -------------------------------- ### Define keyfun type Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.html Defines the function signature for custom bucket key generation. ```elixir @type keyfun() :: (Ash.Query.t() | Ash.Changeset.t() | Ash.ActionInput.t() -> String.t()) | (Ash.Query.t() | Ash.Changeset.t() | Ash.ActionInput.t(), map() -> String.t()) ``` -------------------------------- ### Define rate_limit_options type Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.BuiltinPreparations.html Defines the configuration structure for rate limiting, including limits, time periods, and lifecycle hooks. ```elixir @type rate_limit_options() :: [ limit: pos_integer(), per: pos_integer(), key: String.t() | AshRateLimiter.keyfun(), on: :before_action | :before_transaction ] ``` -------------------------------- ### Handle LimitExceeded Exception Source: https://hexdocs.pm/ash_rate_limiter/index.html Pattern match on the LimitExceeded exception to handle rate limit violations. ```elixir case MyApp.create_post(attrs) do {:ok, post} -> # Success {:ok, post} {:error, %AshRateLimiter.LimitExceeded{} = error} -> # Rate limit exceeded {:error, "Too many requests, please try again later"} {:error, other_error} -> # Handle other errors {:error, other_error} end ``` -------------------------------- ### Retrieve rate limit DSL entities Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.Info.html Returns a list of rate limit structures defined in the DSL. ```elixir @spec rate_limit(dsl_or_extended :: module() | map()) :: [struct()] ``` -------------------------------- ### rate_limit(options) Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.BuiltinChanges.html Adds a rate-limit change directly to an action. This function returns a tuple containing the Change module and the provided options. ```APIDOC ## rate_limit(options) ### Description Adds a rate-limit change directly to an action. ### Signature `rate_limit(rate_limit_options()) :: {AshRateLimiter.Change, rate_limit_options()}` ### Parameters - **options** (rate_limit_options) - Required. A keyword list containing: - **limit** (pos_integer) - Required. The maximum number of events allowed within the given scale. - **per** (pos_integer) - Required. The time period (in milliseconds) for which events are counted. - **key** (String.t | AshRateLimiter.keyfun) - Optional. The key used to identify the event. Defaults to `&AshRateLimiter.key_for_action/2`. - **on** (:before_action | :before_transaction) - Optional. The lifecycle hook to use. Defaults to `:before_action`. ``` -------------------------------- ### Define rate_limit function specification Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.BuiltinPreparations.html Specifies the function signature for adding a rate-limit preparation to an action. ```elixir @spec rate_limit(rate_limit_options()) :: {AshRateLimiter.Preparation, rate_limit_options()} ``` -------------------------------- ### Define AshRateLimiter.LimitExceeded exception specification Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.LimitExceeded.html Defines the structure and types for the LimitExceeded exception, which is returned when rate limits are breached. ```elixir @spec exception(opts :: Keyword.t()) :: %AshRateLimiter.LimitExceeded{ __exception__: true, action: term(), backend: term(), bread_crumbs: term(), class: term(), key: term(), limit: term(), path: term(), per: term(), splode: term(), stacktrace: term(), vars: term() } ``` -------------------------------- ### rate_limit(dsl_or_extended) Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.Info.html Retrieves the rate limit DSL entities from the provided module or map. ```APIDOC ## rate_limit(dsl_or_extended) ### Description Retrieves the rate limit DSL entities from the provided module or map. ### Signature `rate_limit(dsl_or_extended :: module() | map()) :: [struct()]` ``` -------------------------------- ### Define t type Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.html Represents the configuration structure for the AshRateLimiter extension. ```elixir @type t() :: %AshRateLimiter{ __identifier__: any(), __spark_metadata__: Spark.Dsl.Entity.spark_meta(), action: atom(), description: nil | String.t(), key: String.t() | keyfun(), limit: pos_integer(), on: term(), per: pos_integer() | Duration.t() } ``` -------------------------------- ### Define hit/3 callback signature Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.Backend.html The required callback signature for the rate limiting backend. ```elixir @callback hit(key :: String.t(), window_ms :: pos_integer(), limit :: pos_integer()) :: {:allow, pos_integer()} | {:deny, pos_integer()} ``` -------------------------------- ### Define rate_limit function specification Source: https://hexdocs.pm/ash_rate_limiter/AshRateLimiter.BuiltinChanges.html Specifies the function signature for adding a rate-limit change to an action. ```elixir @spec rate_limit(rate_limit_options()) :: {AshRateLimiter.Change, rate_limit_options()} ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.