slouchpie

slouchpie

Using Phoenix forms with Absinthe @graphql attribute in controller

I have finished reading Craft GraphQL APIs in Elixir with Absinthe (Pragprog) and I am trying to expand upon the item_controller.ex to allow for “menu item” editing.

I have made these functions in the controller:

  @graphql """
  query ($id: ID!) {
  menu_item(id: $id) @put {
  name
  description
  }
  }
  """
  def edit(conn, %{data: %{menu_item: item}}) do
    render(conn, "edit.html", item: item)
  end

  @graphql """
  mutation UpdateMenuItem($id: ID!, $input: MenuItemInput!) {
    updatedMenuItem: updateMenuItem(id: $id, input: $input) {
      errors { key message }
      menuItem {
        name
        description
        price
      }
    }
  }
  """
  def update(conn, %{data: %{menu_item: _}}) do
    conn
    |> redirect(to: "/admin/items")
  end
  def update(conn, %{errors: errors}) do
    conn
    |> put_flash(:info, Enum.reduce(errors, "", fn e, a -> a <> e.message end))
    |> redirect(to: "/admin/items")
  end

Here is my edit.html.eex:

<%= render "form.html",
Map.put(assigns, :action,
Routes.item_path(@conn, :update, @item)) %>

Here is my form.html.eex:

<%= form_for @conn, @action, [method: :put, as: :input], fn f -> %>
    <div class="form-group">
        <label for="description">Description</label>
        <input type="string" id="description" as="description" name="description" value="<%= @item.description %>"/>
        <label for="price">price</label>
        <input type="string" id="price" name="price" value="<%= @item.price %>"/>
        <label for="name">name</label>
        <input type="string" id="name" name="name" value="<%= @item.name %>"/>
        <label for="category">category</label>
        <input type="string" id="category" name="categoryId" value="<%= @item.category_id %>"/>
    </div>
    <%= submit "Update", class: "btn btn-primary" %>
<% end %>

But I get an error when I submit the form. This is the error:

In argument "input": Expected type "MenuItemInput!", found null.
Variable "input": Expected non-null, found null.

It makes sense to me. I could, for example change the name attribute of any of the input elements in form.html.eex to be "input" and then I would get a different error:

Argument "input" has invalid value $input.

Again, it makes sense to me. The $input argument is not a MenuItemInput variable.

So I am looking to approach this in either of 2 possible ways:

  1. In the form.html.eex, I create a “form within a form” so that it has an “input” field which, in turn, has several fields.

  2. In the item_controller I pass variables into the @graphql module attribute. I simply don’t know how to do this. I experimented with a lot of strange syntax because I cannot even find examples of SDL that have the variables inline.

Any advice/criticism/ideas are very welcome. I’m sure somebody else has done this since it seems like a natural thing to try after finishing the book.

Marked As Solved

slouchpie

slouchpie

I answered my own question! I just had to change my @graphql query to this:

  mutation UpdateMenuItem($id: ID!, $description: String!, $name: String!, $price: Decimal!, $categoryId: ID!) {
    update_menu_item(id: $id, input: {description: $description, name: $name, price: $price, categoryId: $categoryId}) {
      errors { key message }
      menu_item {
        name
        description
        price
      }
    }
  }

So it seems you cannot really use custom input types like MenuItemInput when using this @graphql module attribute in Phoenix controllers. Also I had to use snake-case for the field names.

P.S. I changed my controller update function signature to this:

def update(conn, %{data: %{update_menu_item: %{errors: nil, menu_item: menu_item}}}) do

Also Liked

slouchpie

slouchpie

Still talking to myself 1 month later…
I tried writing a test to recreate the problem:

I hope this might help any of the core Absinthe team looking into this.

Where Next?

Popular in Questions Top

lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
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
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
Phillipp
Hey, I have a NanoPi-M3 and try to install Elixir on their Ubuntu image. I followed the Raspberry Pi installation instructions from the ...
New
gonzofish
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

Other popular topics Top

Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
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
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New

We're in Beta

About us Mission Statement