Phoenix Basic return fails

I’m running into an issue when trying to return a page with Phoenix. When I return a string it works but when it’s just an integer it fails. Are there only certain return types that are allowed with Phoenix? Below are some examples

This code works

defmodule TapiocaWeb.RandomController do
  use TapiocaWeb, :controller

  import Tapioca.Random

  def index(conn, _params) do
    x = random_number()
    IO.puts(x)
    tuple = {x}
    send_resp(conn, 200, "Number #{x}")
  end
end

But this returns an error

defmodule TapiocaWeb.RandomController do
  use TapiocaWeb, :controller
  import Tapioca.Random

  def index(conn, _params) do
    x = random_number()
    IO.puts(x)
    tuple = {x}
    send_resp(conn, 200, x)
  end
end

random.ex file

defmodule Tapioca.Random do
  def random_number do
    Enum.random(100..10000)
  end
end

send_resp in a Phoenix controller is Plug.Conn.send_resp, which is a lower-level API that expects the response body in a ready-to-send format (iodata).

For instance, if you were sending a JSON response with send_resp you’d need to handle the JSON-encoding part explicitly.

1 Like

Suggestions from a rookie:

TL;DR Use html or json instead of send_resp, e.g. html(conn, "Some response").

To answer your question about return types (it doesn’t solve your immediate problem but it’s helpful to know), controllers “expect” to return a conn. If a conn is not returned, the response (whatever it may be) can be passed to a fallback controller.

The fallback controller catches whatever was returned by the controller (typically in the format {:error, some_value_related_to_the_error}) and dispatches it to some error handler or another, like a changeset error handler, or a generic error handler for a given HTTP status code, e.g. 404, and then that will render the final error view.

1 Like

…and if you look at the definition of Plug.Conn.send_resp/3, the third argument, body, has to be of type body(). Huh? Erlang specifies types with parentheses after the type name, and elixir continues with that nomenclature. So, what is type body()? The docs say body() is the same as the type iodata(), and the iodata() type is specified as iolist() | binary(), i.e. the third argument to Plug.Conn.send_resp must be an iolist() type OR a binary() type. In elixir, the binary() type is a double quoted string.

What about the iolist() type? That is probably the hardest type to understand in elixir/erlang, but in elixir it’s essentially a list containing integers 0-255 and/or double quoted strings that can be nested in sublists, for example:

["hello", [0, "goodbye", [97,98,99]], 255, ["yes", ["no"]] ]

Because the body() type must be either a double quoted string or a list containing specific things, a single integer is not the required type necessary for the third argument of Plug.Conn.send_resp/3.

After troubleshooting a function for awhile, at some point you should check to make sure that the types you are providing as arguments are the required types.

3 Likes