GregMefford

GregMefford

Handling validation of function parameters

I’m working on the next iteration of the API for my nerves_neopixel library and I’m curious how people feel about having an API where there are descriptive error types for invalid arguments as opposed to just using some basic guard clauses and/or just taking whatever the client passes in and “letting it crash” if they put in something that turns out to be invalid?

Should I move the validations inside the GenServer callbacks? I was trying to convince myself that that’s “private” and I should only worry about stuff coming through this public API.

This GenServer is ultimately calling a C port (that I wrote so I can change) that re-validates things, which got me thinking whether I should just remove all the rest of the validation and have the C code return an error message that gets passed all the way up the stack and back to the client.

  @doc """
  Set the color of the pixel at a given point on the virtual canvas.
  """
  @spec set_pixel(Point.t(), Color.t()) ::
    :ok |
    {:error, :invalid, :point} |
    {:error, :invalid, :color}
  def set_pixel(%Point{} = point, %Color{} = color) do
    with \
      :ok <- validate_point(point),
      :ok <- validate_color(color),
    do: GenServer.cast(HAL, {:set_pixel, point, color})
  end

  # ...

  defp validate_point(point, tag \\ :point)
  defp validate_point(%Point{x: x, y: y}, _tag) when x in 0..65535 and y in 0..65535, do: :ok
  defp validate_point(_point, tag), do: {:error, :invalid, tag}

  defp validate_color(%Color{r: r, g: g, b: b, w: w}) when r in 0..255 and g in 0..255 and b in 0..255 and w in 0..255, do: :ok
  defp validate_color(_), do: {:error, :invalid, :color}

Most Liked

cmkarlsson

cmkarlsson

My preference is to validate external data and turn into a “known” data structure at the edges, and let it crash once you know you have good data. I think this applies a bit more to the case where you have truly external data such as console input or tcp data but also to your public API of your library.

I personally don’t care to much about the error message from a library. I.e :badarg is OK as I then can look up the documentation.

If you are going to “let it crash” or not on bad input depends on the consequences of the crash and if it is only going to happen during development or if it can happen in production. It is used quite a bit in OTP libraries so I guess it OK to do so :smiley:

Where Next?

Popular in Questions Top

chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: The documentation above suggests that while ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New

Other popular topics Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
senggen
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
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43622 214
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New

We're in Beta

About us Mission Statement