A repository of bitesize articles, tips & tricks
(in both English and French) curated by Mirego’s team.

Refactor List.first/0 into a better flow

I’ve always heard that List.first/0 is not the most Elixir-esque pattern out there — that there almost always is a better pattern to use instead.

So when I encountered this code:

conn
|> Plug.Conn.get_req_header("x-some-header")
|> List.first()
|> case do
  nil -> nil
  value -> String.to_integer(value)
end

I thought to myself “There’s gotta be a better way”!

My first reflex was to use pattern matching to extract the first element of the list and let the fallback _ handle everything else:

conn
|> Plug.Conn.get_req_header("x-some-header")
|> case do
  [value | _] -> String.to_integer(value)
  _ -> nil
end

But @simonprev came up with a better solution.

We really should be using with to control the flow and make sure that both the header and its converted value are exactly what we expect, then let it fallback to nil in case they aren’t.

with [value | _] <- Plug.Conn.get_req_header(conn, "x-some-header"),
     {integer, _} <- Integer.parse(value) do
  integer
else
  _ -> nil
end

Much more robust and easier to comprehend 🙌