How to use get_in to retrieve Item name from [%{"id" => "1849", "name" => "Reuben"}]

Hi everyone,

How can i retrieve the name from a structure like this?

 %{"id" => "1570", "name" => "Croque Monsieur"}

My test looks like this

describe "GetMenuItems.gql == matching" do
    test "Should return all Menu items (1 of them)" do
      result = query_gql(variables: %{"matching" => "reu"})
      assert {:ok, %{data: %{"MenuItems" => menu_items}}} = result
      IO.inspect(menu_items)

      assert length(menu_items) == 1

      assert menu_items == [%{"name" => "Reuben", "id" => 1471}]
    end
  end

What i tried:

name = get_in(menu_items, [:name])

name = get_in(result, [:data, "MenuItems", "name"])

So can someone explain to me the correct way to do this?

Thanks

If you have a list of menu items then you need to use Access.at/1.

2 Likes

As @Eiji mentions a list would require Access.at/1

The other way would be to use get_in with a function as key (see
Kernel — Elixir v1.16.0 )

If you always expect exactly one result at this point you can also do it like this:
Screenshot 2020-02-04 at 16.28.49

Hope I helped you :slight_smile:

1 Like

Thanks @Eiji for the link.

Thanks @Aduril for providing context to my question and helping me realize what options i can use to achieve this. Really appreciate it,

Unfortunately it doesn’t work

name = get_in(menu_items, [Access.at(1), :name]) I get nil

"name" is not the same as :name, which key are you looking for?

Your initial post mentions "name", your last though uses :name…

Still not working

name = get_in(menu_items, [Access.at(1), "name"])

I need to get the name from the following struct to use in an assert

[%{"id" => "1849", "name" => "Reuben"}]

So i want to use assert name == "Reuben" to match

Access.at is zero indexed.

2 Likes

You are right. How stupid of me to forget. Now it works

1 Like

Also what is the difference between

name = get_in(menu_items, [Access.at(1), "name"]) like this and

name = get_in(menu_items, [Access.at(1), :name])

Aren’t they both atoms here?

"name" is a string, :name is an atom.

On a larger note though, I really don’t recommend using get_in like this to test API responses. The reason is that if things don’t go as you expect, either because you have a bug in your test code, or because your API isn’t returning what you expect, the error messages don’t tell you anything.

I always test my GraphQL apis using a combination of = and == eg:

assert {:ok, %{data: %{"MenuItems" => menu_items}}} = result
assert menu_items == [%{"name" => "Reuben", "id" => 1471}]

This is so much better than using get_in because if result doesn’t match, the error message will tell you what result actually is. Then if the name isn’t "Reuben", once again the failure message will show you the whole thing.

3 Likes

Thanks

But unfortunately this doesn’t work

assert menu_items == [%{"name" => "Reuben", "id" => 1471}]

I get a new id every time with Wormwood, when I run a new test.

something like this

Error trace:

 1) test GetMenuItems.gql == matching Should return all Menu items (1 of them) (PlateSlateWeb.Schema.Query.MenuItemsTest)
     test/plate_slate_web/schema/query/menu_items_test.exs:23
     Assertion with == failed
     code:  assert menu_items == %{"id" => "1877", "name" => "Reuben"}
     left:  [%{"id" => "1905", "name" => "Reuben"}]
     right: %{"id" => "1877", "name" => "Reuben"}
     stacktrace:
       test/plate_slate_web/schema/query/menu_items_test.exs:36: (test)



Finished in 1.1 seconds
2 tests, 1 failure

Ah, yeah then use =.

assert [%{"name" => "Reuben", "id" => _}] = menu_items

Alternatively, don’t ask for id in the GraphQL query.

1 Like

Cool thanks very much didn’t know you could ignore a value in a pattern matching struct.

1 Like

Maps are special in pattern matching; you can ignore id as well by doing this:

%{"name"=>"foo"} = my_map

The difference being Ben’s match enforces the presence of an id field but not its value, and mine enforces neither.

2 Likes

Thanks for sharing my life will become easier now.