t56k
t56k

Reputation: 6981

Phoenix: API controller gets error regardless of params

I've got a controller that looks like this:

defmodule PrefectWeb.DocumentController do
  use PrefectWeb, :controller

  alias Prefect.Queue

  def create(conn, params) do
    case Prefect.add(Queue, struct(Prefect.Document, params[:id])) do
      nil -> conn 
        |> put_status(404) 
        |> render("error.json")
      status -> {:ok, status}
    end
  end
end

The create method is supposed to add the params[:id] to the Queue process. My unit test looks like this:

defmodule PrefectWeb.DocumentControllerTest do
  use ExUnit.Case, async: true
  use PrefectWeb.ConnCase

  setup do
    params = [
      env: "test",
      id: 1,
    ]

    [params: params]
  end

  test "creation", %{conn: conn, params: params} do
    conn
    |> post(document_path(conn, :create, params))

    assert json_response(conn, 422)
  end
end

This spec returns this error:

1) test creation (PrefectWeb.DocumentControllerTest)
   test/prefect_web/controllers/document_controller_test.exs:27
   ** (Protocol.UndefinedError) protocol Enumerable not implemented for nil. This protocol is implemented for: Date.Range, File.Stream, Function, GenEvent.Stream, HashDict, HashSet, IO.Stream, List, Map, MapSet, Range, Stream

If I change the controller function to his:

def create(conn, %{"params" => params}) do
  ...
end

I get this error:

1) test creation (PrefectWeb.DocumentControllerTest)
     test/prefect_web/controllers/document_controller_test.exs:27
     ** (Phoenix.ActionClauseError) could not find a matching PrefectWeb.DocumentController.create clause
     to process request. This typically happens when there is a
     parameter mismatch but may also happen when any of the other
     action arguments do not match. The request parameters are:

       %{"env" => "test", "id" => "1"}

Why can't I pass the params[:id] to the create method correctly?

Update

Adding request headers doesn't help either:

|> put_req_header("content-type", "application/json")

Upvotes: 1

Views: 954

Answers (2)

Phillipp
Phillipp

Reputation: 1445

The params map is string and not atom based. Try changing your controller to

defmodule PrefectWeb.DocumentController do
  use PrefectWeb, :controller

  alias Prefect.Queue

  def create(conn, params) do
    case Prefect.add(Queue, struct(Prefect.Document, params["id"])) do
      nil -> conn 
        |> put_status(404) 
        |> render("error.json")
      status -> {:ok, status}
    end
  end
end

and your test to

defmodule PrefectWeb.DocumentControllerTest do
  use ExUnit.Case, async: true
  use PrefectWeb.ConnCase

  setup do
    params = %{
      "env" => "test",
      "id" => 1
    }

    [params: params]
  end

  test "creation", %{conn: conn, params: params} do
    conn
    |> post(document_path(conn, :create, params))

    assert json_response(conn, 422)
  end
end

Upvotes: 1

Mike Buhot
Mike Buhot

Reputation: 4885

You are asserting on the conn created in setup, instead of the one returned from post. Try re-binding the conn before the assert.

  test "creation", %{conn: conn, params: params} do
    conn = 
      conn
      |> post(document_path(conn, :create), params)

    assert json_response(conn, 422)
  end

Upvotes: 0

Related Questions