No function clause matching UserController.create Method when POSTing

I am trying to post a test user account to the users table in the repo but I am getting the ‘no function clause matching’ error for some reason.

I have tried POSTing on both curl and Postman with the same results. Here is my post using CURL:
curl -H "Content-Type: application/json" -X POST -d '{"name":"test","id":"5"}' http://localhost:4000/api/users2

Another trial of CURL (in the style of the tutorial I am using - https://pamit.medium.com/building-a-restful-backend-with-elixir-phoenix-84fe390975c - uses):
curl -X POST http://localhost:4000/api/users2 -H “Content-Type: application/json” -d ‘{“accounts”: {“name”: “test”, “id”: “5"}}’

In Postman I am writing the URL with the JSON in the body:

http://localhost:4000/api/users2
{"name":"test","id":"5"}

Here is my create method which should be matching in order to add the new user account:

def create(conn, %{"user" => user_params}) do
    with {:ok, %User{} = user} <- Accounts.create_user(user_params) do
      conn
      |> put_status(:created)
      |> put_resp_header("location", Routes.user_path(conn, :show, user))
      |> render("show.json", user: user)
    end
  end

Your create function is not matching the parameters that you are sending via curl. A possible fix is to change the first line from:

def create(conn, %{"user" => user_params}) do

to:

def create(conn, %{"accounts" => user_params}) do

Although personally i prefer to do little to no matching in controller function heads because I find the no function clause matching not very informative. If you changed your create to function to:

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

Then you would have gotten a more informative pattern matching error.

Hi Axelson, many thanks for the reply! I am pretty new to Elixir and API calling so forgive me for my naivity but I have made the changes and am now getting an ‘undefined function’ error:

CompileError
lib/bank_api_web/controllers/user_controller.ex:26: undefined function user/0
Console output is shown below.
Compiling 1 file (.ex)

== Compilation error in file lib/bank_api_web/controllers/user_controller.ex ==
** (CompileError) lib/bank_api_web/controllers/user_controller.ex:26: undefined function user/0
    (elixir 1.11.2) src/elixir_locals.erl:114: anonymous fn/3 in :elixir_locals.ensure_no_undefined_local/3
    (stdlib 3.13.2) erl_eval.erl:680: :erl_eval.do_apply/6
    (elixir 1.11.2) lib/kernel/parallel_compiler.ex:314: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7

THis is now my create method:

 def create(conn, params) do
    %{"accounts" => user_params} = params
    |> put_status(:created)
    |> put_resp_header("location", Routes.user_path(conn, :show, user))
    |> render("show.json", user: user)
  end

It does not look like the code in the blog You are following… which looks like this

def create(conn, %{"business" => business_params}) do
  with {:ok, %Business{} = business} <- Directory.create_business(business_params) do
    conn
    |> put_status(:created)
    |> put_resp_header("location", business_path(conn, :show, business))
    |> render("show.json", business: business)
  end
end

Anyway, I would not recommend to follow this (old) post because things have changed since.

Maybe try this one, which cover Phoenix 1.5

https://lobotuerto.com/blog/building-a-json-api-in-elixir-with-phoenix/

BTW You are using user variable, which was never defined, and You define user_params, which is never used.

Hi, thanks for your help. I have gone through the tutorial you suggested but find myself at the stage stage once more of trying to POST to my create_user route.

Here is my create function:

def create(conn, %{"user" => user_params}) do
    with {:ok, %User{} = user} <- Account.create_user(user_params) do
      conn
      |> put_status(:created)
      |> put_resp_header("location", Routes.user_path(conn, :show, user))
      |> render("show.json", user: user)
    end
  end

And this is the error in Postman:

no function clause matching in SpBankWeb.UserController.create/2
The following arguments were given to SpBankWeb.UserController.create/2:

    # 1
    %Plug.Conn{adapter: {Plug.Cowboy.Conn, :...}, assigns: %{}, before_send: [#Function<0.11227428/1 in Plug.Telemetry.call/2>], body_params: %{"amount" => "5.0", "name" => "test2"}, cookies: %{}, halted: false, host: "localhost", method: "POST", owner: #PID<0.471.0>, params: %{"amount" => "5.0", "name" => "test2"}, path_info: ["api", "users"], path_params: %{}, port: 4000, private: %{SpBankWeb.Router => {[], %{}}, :phoenix_action => :create, :phoenix_controller => SpBankWeb.UserController, :phoenix_endpoint => SpBankWeb.Endpoint, :phoenix_format => "json", :phoenix_layout => {SpBankWeb.LayoutView, :app}, :phoenix_request_logger => {"request_logger", "request_logger"}, :phoenix_router => SpBankWeb.Router, :phoenix_view => SpBankWeb.UserView, :plug_session_fetch => #Function<1.123471702/1 in Plug.Session.fetch_session/1>}, query_params: %{}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %{}, req_headers: [{"accept", "*/*"}, {"accept-encoding", "gzip, deflate, br"}, {"connection", "keep-alive"}, {"content-length", "31"}, {"content-type", "application/json"}, {"host", "localhost:4000"}, {"postman-token", "dba91f4a-d119-4ce9-a866-4be4fcc2a5b8"}, {"user-agent", "PostmanRuntime/7.26.8"}], request_path: "/api/users", resp_body: nil, resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "FkraqL6-WjCGiuEAAACh"}], scheme: :http, script_name: [], secret_key_base: :..., state: :unset, status: nil}

    # 2
    %{"amount" => "5.0", "name" => "test2"}

SOLVED: Inside the body of the HTML post on Postman, you need to include the exact variable name that the controller function uses (in my case this is ‘user’).

{“user”:{“name”:“test2”,“amount”:“5.0”}}

^^ This worked!

Thanks all who helped