ycherniavskyi
Collect all function return tuples in the module with macro and provide access to them with a helper function
Let’s say I have next controller where {:error, _, _} action result processed by FallbackController:
defmodule SomeProjectWeb.Api.V1.SessionController do
use SomeProjectWeb, :controller
alias SomeProject.Session
alias SomeProject.Session.Otp
alias SomeProjectWeb.Api.V1.CastAndValidateRenderError
alias SomeProjectWeb.Api.V1.FallbackController
alias SomeProjectWeb.Api.V1.{CommonSchema, SessionSchema}
plug(OpenApiSpex.Plug.CastAndValidate, render_error: CastAndValidateRenderError)
action_fallback(FallbackController)
tags(["session"])
def action(conn, _) do
apply(__MODULE__, action_name(conn), [conn, conn.params, conn.body_params])
end
operation(:otp_create,
summary: "otp_create summary",
description: "otp_create description",
requestBody: {
"request body description",
"application/json",
SessionSchema.OtpCreateRequest,
required: true
},
responses: [
ok: {
"ok description",
"application/json",
SessionSchema.OtpCreateResponse
},
unauthorized: "...",
unprocessable_entity: {
"Unprocessable Content, ...",
"application/json",
%Schema{
allOf: [
CommonSchema.ErrorResponse,
%Schema{
type: :object,
properties: %{
code: %Schema{
enum: [
:no_otp_delivery_channel,
:runout_signup_account
]
}
}
}
]
}
},
internal_server_error: {
"Internal Server Error, ...",
"application/json",
%Schema{
allOf: [
CommonSchema.ErrorResponse,
%Schema{
type: :object,
properties: %{
code: %Schema{
enum: [
:external_api,
:demo_account_manager
]
}
}
}
]
}
}
]
)
def otp_create(conn, _params, %{user_email: email} = _body_params) do
case SomeProject.DemoAccountManager.retrieve(email) do
{:ok, i_account} ->
case SomeProject.ExternalApi.create_otp(i_account) do
{200, %{"success" => 1, "type" => "email", "from" => email}} ->
otp = Session.create_otp(%{i_account: i_account, demo: true})
render(conn, otp_id: otp.id, type: "email", from: email)
{500, %{"faultcode" => "channel-error"}} ->
{:error, :unprocessable_entity, :no_otp_delivery_channel}
_ ->
{:error, :internal_server_error, :external_api}
end
{:error, :runout} ->
{:error, :unprocessable_entity, :runout_signup_account}
{:error, _} ->
{:error, :internal_server_error, :demo_account_manager}
end
end
end
For now, I manually sync possible error codes for each result with relative result schema. That is diffidently not convenient and will lead to unsync in the future.
I want to implement some type of module macro that will collect and group all its functions :error results and introduce the helper function to access them.
So I could replace:
internal_server_error: {
"Internal Server Error, ...",
"application/json",
%Schema{
allOf: [
CommonSchema.ErrorResponse,
%Schema{
type: :object,
properties: %{
code: %Schema{
enum: [
:external_api,
:demo_account_manager
]
}
}
}
]
}
}
with:
internal_server_error: {
"Internal Server Error, ...",
"application/json",
%Schema{
allOf: [
CommonSchema.ErrorResponse,
%Schema{
type: :object,
properties: %{
code: %Schema{
enum: error_codes(:otp_create, :internal_server_error)
}
}
}
]
}
}
(for sure such the final helper function could produce a more significant piece of repetitive code, but here I want to highlight its core functionality)
What is the best way to implement such functionality?
Popular in Questions
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1]
15:22:35.803 [error] gen_event {lager_file_backend...
New
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
can someone please explain to me how Enum.reduce works with maps
New
Hey all, just started picking up Elixir last week and am writing a scraper as a learning project.
Baby step #1 is extracting the number ...
New
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
Hello everybody,
usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
Hi guys, nice to meet you to the whole forum, I’m new here, I’m trying to configure visual studio code for elixir, right now the intellis...
New
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
Sometimes I want to check if the input into a function is not a blank string.
My first approach:
defmodule Example do
def do_stuff(s...
New
Other popular topics
Update:
How to use the Blogs & Podcasts section
You can post links to your blog posts or podcasts either in one of the Official Blog...
New
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
Hi,
I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
What is the idiomatic way of matching for not nil in Elixir?
E.g.,
First way:
defp halt_if_not_signed_in(conn, signed_in_account) when...
New
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!)
This post collects co...
New
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
New
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum.
...
New
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New








