Absinthe and arbitrary Data

Hello there!
I’m developing my CRUD api with phoenix and absinthe and I consider about how write schema without specific type. For instance: I have “map” object includes keys as name, description and “data”. The data should has “any” type cuz it depends on external program.
Is it possible in Absinthe?

I would say no, because GraphQL is strongly typed, and does not support the type any.

1 Like

This is true, but you can sort of create one by using a JSON scalar: https://github.com/absinthe-graphql/absinthe/wiki/Scalar-Recipes#json-using-jason

3 Likes

Note that the particular implementation of the JSON scalar there will probably have problems with Apollo on iOS—and possibly Android—because it’s a map inbound (to the client) and a string outbound (to the server). I had specified that as a Map type, but have deprecated it in our type definitions preferring to specify a JSON scalar that always encodes to a JSON-encoded string and decodes from the same. It makes for more uniform handling on clients.

So if I have a field that is a list of maps, say like the one below:

@desc "An answer"
  object :answer do
    field :body, non_null(:string), description: "The answer body"
    field :is_correct, non_null(:boolean), default_value: false
  end

  @desc "A question"
  object :question do
    field :id, non_null(:id) # ID!
    field :body, non_null(:string), description: "The question body"
    field :answers_array, non_null(list_of(non_null(:answer)))
  end

and my schema is as as follows:

  schema "questions" do
    field :answers_array, {:array, :map}
    field :body, :string

    timestamps()

Will I have to use the JSON scalar to represent the :answers_array attribute (which is an array of maps) to avoid “Cannot return null for non-nullable field” errors when retrieving any answers for a question?

Your issue here is more likely that the map coming from a jsonb column has string keys, whereas absinthe fields by default expect atom keys. You can solve this by using a custom resolver or middleware.

  object :answer do
    field :body, non_null(:string), description: "The answer body", resolve: fn answer, _, _ -> {:ok, answer["body"]} end)
    field :is_correct, non_null(:boolean), default_value: false, resolve: fn answer -> _, _ -> {:ok, answer["is_correct"]} end)
  end
2 Likes

Wow, yes that helped me exactly, thank you : ). I’ve been reading your book on how to incorporate Absinthe In Phoenix alongside React and just realized you go over this exact problem at the end of Chapter 7. I realize now that it’s an issue with the default resolver for maps, and I should write a custom resolver or middleware default resolver for this type exactly like you suggested. Thank you so much again (I wish the error that GraphiQL was showing was more lucid and pointed me in this direction).