marisradu

marisradu

Disclaimer: I’m new (still learning) elixir.
Can’t figure how to DRY this code out, I would like to capture the “message” from all blocks and then send the response and halt the connection.

Original code:

def call(conn, _) do
    case some_function(conn) do
      {:ok, response} ->
        put_private(conn, :my_app, %{my_key: response})

      {:error, :error_1 ->
        conn
        |> put_resp_content_type("application/json")
        |> send_resp(403, "Message for error 1")
        |> halt

      {:error, :error_2} ->
        conn
        |> put_resp_content_type("application/json")
        |> send_resp(403, "Message for error 2")
        |> halt

      _ ->
        conn
        |> put_resp_content_type("application/json")
        |> send_resp(403, "Generic message")
        |> halt
    end
  end

I wanted to put everything in a with statement like:

with {:ok, response} <-  some_function(conn) do
     put_private(conn, :my_app, %{my_key: response})
else
     {:error, :error_1} ->
        message = "Message for error 1"
     {:error, :error_2} ->
        message = "Message for error 2"
      _ ->
        message = "Generic message"
    end

I’m pretty sure there is a better way to capture the “message” and also not sure where to put the “response” as inside the “else” clause will need to put it for all clauses, outside will also be triggered if there is no error.

conn
|> put_resp_content_type("application/json")
|> send_resp(403, message)
|> halt

Any hint or constructive criticism in case you think I’m going in the wrong direction will be appreciated.
Thanks.

Showing Posts 1 to 9

LostKobrakai

LostKobrakai

Using with was already a good idea, but sometimes just using one flow control type is just not enough:

def call(conn, _) do
	with {:ok, response} <- some_function(conn) do
		put_private(conn, :my_app, %{my_key: response})
	else
		err -> 
			message =
			  case err do
					{:error, :error_1} -> "Message for error 1"
					{:error, :error_2} -> "Message for error 2"
					_ -> "Generic message"
				end

			conn
			|> put_resp_content_type("application/json")
			|> send_resp(403, message)
			|> halt
	end
end
hubertlepicki

hubertlepicki

Generally if you also do format the code (buttons above or with indentation) properly you get better chance of people responding - it’s quite difficult to decipher not formatted code and programmers are obviously lazy :slight_smile:

marisradu

marisradu OP

Damn … did do that, but missed to check in the preview pane.
Definitely going to get a strong coffee now.

Thanks for the notification.

mbuhot

mbuhot

When in doubt, use more functions :grinning_face_with_smiling_eyes:

def call(conn, _) do
  with {:ok, response} <- some_function(conn) do
    put_private(conn, :my_app, %{my_key: response})
  else
    err -> 
      message = error_message(err)
      conn
      |> put_resp_content_type("application/json")
      |> send_resp(403, message)
      |> halt
  end
end
    
defp error_message({:error, :error_1}), do: "Message for error 1"
defp error_message({:error, :error_2}), do: "Message for error 2"
defp error_message(_), do: "Generic message"
idi527

idi527

I don’t see much reason to use with when a flat case would be enough (as in your case).

Nicd

Nicd

Yes, iterating on the last response:

def call(conn, _) do
  case some_function(conn) do
    {:ok, response} ->
      put_private(conn, :my_app, %{my_key: response})

    err -> 
      message = error_message(err)
      conn
      |> put_resp_content_type("application/json")
      |> send_resp(403, message)
      |> halt
  end
end
    
defp error_message({:error, :error_1}), do: "Message for error 1"
defp error_message({:error, :error_2}), do: "Message for error 2"
defp error_message(_), do: "Generic message"
LostKobrakai

LostKobrakai

I’m mostly of the same opinion, but with might communicate a bit more the monad-like success/error railway-ing while case is a bit more “equal cases” in it’s semantics. Especially in plugs where one branch does halt the pipeline I see myself more drawn to using with.

peerreynders

peerreynders

I sense a lack of commitment :grin:

def call(conn, _) do
  with {:ok, response} <- some_function(conn) do
    put_private(conn, :my_app, %{my_key: response})
  else
    err -> 
      call_error(err, conn)
  end
end
    
defp call_error({:error, :error_1}, conn), do: forbidden_response(conn, "Message for error 1")
defp call_error({:error, :error_2}, conn), do: forbidden_response(conn, "Message for error 2")
defp call_error(_, conn), do: forbidden_response(conn)

defp forbidden_response(conn, msg \\ "Generic Message"), do: error_response(conn, 403, msg)

defp error_response(conn, status, msg) do
  conn
  |> put_resp_content_type("application/json")
  |> send_resp(status, msg)
  |> halt
end
idi527

idi527

but with might communicate a bit more the monad-like success/error railway-ing

That’s a really nice way to think about it.

— All posts loaded —

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
achenet
Hello, I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind. However, when I launch mix phx.server, I get an error...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
Cxx-mlr
I’m working on a small exercise involving update_in/3, and I came up with this solution: data = %{ name: "Periodic Table", category:...
New
ChrisAmelia
I’ve got trouble wrapping my head around the order in which functions are called in this snippet (from Phoenix’s authentication): toke...
New
dillonoconnor
Is there any way to avoid the Hologram compiler running when using iex? It seems like the front-end code could potentially be disregarded...
New
thiagogsr
** (ArgumentError) expected :max_attempts to be a positive integer, got: {:@, [line: 10, column: 19], [{:max_attempts, [line: 10, column:...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews