ExEssentials.Web.Plugs.DisableServices behaviour (ExEssentials v0.4.2)
View SourceA Plug
that conditionally disables specific controller actions based on a feature flag,
with optional support for group-based evaluation using FunWithFlags
.
Overview
This plug allows developers to temporarily disable specific Phoenix actions
(e.g., :create
, :delete
) by checking if a feature flag is enabled for the current context (typically, the current user or realm).
It works by intercepting the connection and returning a 503 Service Unavailable
response if the feature flag is enabled and the requested action is among the disabled ones.
Group-based targeting is supported through FunWithFlags
, using a struct that includes
the current user as current_user
.
Configuration
You must provide the following options when using the plug:
:disabled_actions
– a list of controller actions (atoms) that should be disabled if the flag is active.:flag_name
– the name of the feature flag to check (defaults to:disable_services_enabled
).
This plug uses FunWithFlags.enabled?/2
with a custom context struct that supports group checks via FunWithFlags.Group
.
Dependencies
To use this plug, your application must be configured with:
{:fun_with_flags, "~> 1.13"},
{:ecto_sql, "~> 3.4"},
{:postgrex, ">= 0.0.0"},
And you must configure the FunWithFlags
adapter to use Ecto with a repo.
Usage
Simple usage (default behavior)
By default, the plug uses conn.assigns.user_name
or conn.params["user_name"]
to resolve the group.
plug ExEssentials.Web.Plugs.DisableServices,
disabled_actions: [:create, :delete],
flag_name: :services_disabled
Customized usage with use
and @impl
To change how the group name is extracted from the connection (e.g., use realm
instead of user_name
),
you can define your own module and override the get_current_user/1
callback:
defmodule MyApp.Web.Plugs.DisableServices do
use ExEssentials.Web.Plugs.DisableServices
@impl ExEssentials.Web.Plugs.DisableServices
def get_current_user(%Plug.Conn{assigns: %{realm: realm}}), do: realm
def get_current_user(%Plug.Conn{params: params}), do: Map.get(params, "realm")
def get_current_user(_), do: nil
end
And in your router or endpoint:
plug MyApp.Web.Plugs.DisableServices,
disabled_actions: [:create, :delete],
flag_name: :services_disabled
Example with FunWithFlags
To enable or disable the flag at runtime:
FunWithFlags.enable(:services_disabled)
FunWithFlags.disable(:services_disabled, for_group: "admin")
This will enable the flag globally, but disable it for users in the "admin" group.
Notes
- If
FunWithFlags
is not available at runtime (e.g., not installed), the plug assumes the flag is enabled by default and proceeds with normal request handling. - The
ExEssentials.Web.Plugs.DisableServices
struct implements theFunWithFlags.Group
protocol to support group-based targeting.
Summary
Functions
Callback implementation for Plug.call/2
.
Extracts the current user identifier from the connection for use in group-based flag evaluation.
Callback implementation for Plug.init/1
.
Callbacks
@callback get_current_user(Plug.Conn.t()) :: String.t() | nil
Functions
Callback implementation for Plug.call/2
.
Extracts the current user identifier from the connection for use in group-based flag evaluation.
This function looks first in conn.assigns[:user_name]
, and if not found, in conn.params["user_name"]
.
Examples
iex> conn = %Plug.Conn{assigns: %{user_name: "admin"}}
iex> ExEssentials.Web.Plugs.DisableServices.get_current_user(conn)
"admin"
iex> conn = %Plug.Conn{params: %{"user_name" => "admin"}}
iex> ExEssentials.Web.Plugs.DisableServices.get_current_user(conn)
"admin"
iex> ExEssentials.Web.Plugs.DisableServices.get_current_user(%Plug.Conn{})
nil
Callback implementation for Plug.init/1
.