Skip to content

Instantly share code, notes, and snippets.

@jvantuyl
Last active June 10, 2024 11:14
Show Gist options
  • Select an option

  • Save jvantuyl/913495bf758f3099f27cecc7197de385 to your computer and use it in GitHub Desktop.

Select an option

Save jvantuyl/913495bf758f3099f27cecc7197de385 to your computer and use it in GitHub Desktop.
A Contrived Elixir Early-Return Example
defmodule ContrivedWebHandler do
def handle(request) do
request
|> rate_limit()
|> validate_csrf()
|> get_user()
|> check_password()
|> ensure_permissions()
|> ensure_quota()
|> check_cache()
|> execute_action()
catch
{:fail, request, user, reason} ->
Logger.error(
message: "error handling request",
user: user,
action: request.action,
resource: request.resource
)
{:cached, request, user, result} ->
Logger.info(
message: "request found in cache",
user: user,
action: request.action,
resource: request.resource
)
{:ok, result}
unexpected ->
Logger.error(
message: "unknown return status while handling request",
error: unexpected
)
end
def rate_limit(request) do
if RateLimiter.limited?(request) do
throw({:fail, request, nil, :rate_limit})
end
request
end
def validate_csrf(request) do
if CsrfValidator.valid?(request) do
request
else
throw({:fail, request, nil, :bad_csrf_token})
end
end
def get_user(request) do
if App.authentication_disabled?() do
throw(:ok)
end
case UserService.get_user(request) do
{:ok, user} ->
{request, user}
{:error, reason} ->
throw({:fail, request, nil, reason})
end
end
def check_password({request, user}) do
case UserService.check_password(user, request.password) do
:ok ->
{request, user}
{:error, reason} ->
throw({:fail, request, user, reason})
end
end
def ensure_permissions({request, user}) do
cond do
!user.enabled ->
throw({:fail, request, user, :user_disabled})
user.admin ->
{request, user}
!PermissionChecker.allowed(user, request.action, request.resource) ->
throw({:error, :permission_denied})
true ->
{request, user}
end
end
def ensure_quota({request, user}) do
if !QuotaChecker.has_quota(user, request.action, request.resource) do
throw({:fail, request, user, :quota_exhausted})
end
end
def check_cache({request, user}) do
case Cache.get_cached_result(user, request.action, request.resource) do
{:ok, result} ->
throw({:cached, user, request, result})
{:ok, nil} ->
{request, user}
{:error, reason} ->
throw({:fail, request, user, reason})
end
end
def execute_action({request, user}) do
Logger.info(
message: "executing action",
user: user,
action: request.action,
resource: request.resource
)
action_handler = get_action_handler(request.action)
action_handler.(user, request.resource)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment