How to use Absinthe import_sdl and hydrate functions

Hi, I’m new to Elixir and trying to probe the GraphQL things. I’d like to understand how to use the import_sdl macro with the hydrate function to match resolvers to the imported schema. My sample setup looks like this:

SDL File

type Person {
    lastName: String!
    firstName: String!
    id: String!
    phoneNumbers: [String]
}

type Query {
    getPersonById(id: String!): Person
    getPeople: [Person]!
}

defmodule GqlHydrateWeb.Schema do
  @moduledoc false

  use Absinthe.Schema.Notation

  import_sdl path: "assets/sdl/sample-schema.graphql"

  # Where/how do I call the hydrate function provided with the resolver? Or is that defined here?

end

Resolver File

defmodule GqlHydrateWeb.Resolvers.GetPeople do

  def resolve_get_people(a,b,c) do
    %{
    lastName: 'Smith',
    firstName: 'Joe',
    id: '9ap8sodh'
    }

  end

  # Adapted from the Absinthe Docs
  def hydratePeople(%{identifier: :getPeople}, [%{identifier: :query} | _]) do
    {:resolve, &__MODULE__.resolve_get_people/3}
  end

end

I can write the hydrate function, but I don’t quite know how to integrate that into the schema building process so that this is called within the right context. Is there a sample somewhere that I can look at to see how this pattern can be used?

Your hydate function doesn’t look like ours, so maybe the docs are suggesting a different approach, but our code looks something like this:

defmodule GqlHydrateWeb.Schema do
  @moduledoc false

  use Absinthe.Schema.Notation

  import_sdl path: "assets/sdl/sample-schema.graphql"

  def hydrate(%Absinthe.Blueprint{}, _) do
    %{query: %{get_people: [resolve: &GqlHydrateWeb.Resolvers.GetPeople.resolve_get_people/2]}}
  end

  def hydrate(_node, _ancestors), do: []

end
1 Like

@mayel 's code here looks right to me, I’d be curious about where the docs are that @RoboZoom is following.

1 Like

Ok - I think I understand my misunderstanding. I thought that the sample in the docs was a function that I would attach to a lifecycle hook, when, in fact, it’s literally calling the Schema.hydrate function on initialization. Then you have a hydrate function per required resolver that matches against each node in the schema (as Absinthe will iterate through each node calling hydrate on setup).

Is this accurate?

Can you link to the docs you are following?

I am referencing the docs here: Absinthe.Schema — absinthe v1.7.0

Following the feedback above, here is how I have my server setup:

SDL

type Person {
    lastName: String!
    firstName: String!
    id: String!
    phoneNumbers: [String]
}

type Query {
    getPeople: [Person]!
}

Schema.ex

defmodule GqlHydrateWeb.Schema do
  @moduledoc false

  use Absinthe.Schema.Notation

  import_sdl path: "assets/sdl/sample-schema.graphql"

  def hydrate(%{identifier: :getPeople}, [%{identifier: :query} | _]) do
    {:resolve, &GqlHydrateWeb.Resolvers.GetPeople.resolve_get_people/3}
  end

  def hydrate(_node, _ancestors), do: []
end

When I run the app, and test the API - I get this error:

Server: localhost:4000 (http)
Request: POST /api/graphiql
** (exit) an exception was raised:
    ** (ArgumentError) GqlHydrateWeb.Schema is not a valid `Absinthe.Schema`
        (absinthe_plug 1.5.8) lib/absinthe/plug.ex:258: Absinthe.Plug.get_schema/1
        (absinthe_plug 1.5.8) lib/absinthe/plug.ex:224: Absinthe.Plug.init/1
        (absinthe_plug 1.5.8) lib/absinthe/plug/graphiql.ex:177: Absinthe.Plug.GraphiQL.init/1
        (phoenix 1.6.15) lib/phoenix/router/route.ex:41: Phoenix.Router.Route.call/2
        (phoenix 1.6.15) lib/phoenix/router.ex:354: Phoenix.Router.__call__/2

Any thoughts? I’m clearly brand new to Elixir/Phoenix, and I’m not even sure the right way to debug this.

EDIT: Also, here is the documentation for import_sdl: Absinthe.Schema.Notation — absinthe v1.7.0

Can you post your project to GitHub so that I can take a look?

Absolutely - here is the link: GitHub - RoboZoom/gql_hydrate

Thank you for your help!

This line here gql_hydrate/schema.ex at master · RoboZoom/gql_hydrate · GitHub should be use Absinthe.Schema not use Absinthe.Schema.Notation.

If you are very new to Elixir, and in particular if you are new to functional programming, I would strongly suggest taking a beat to get comfortable with the language before diving into Absinthe as its docs generally expect a general familiarity with Elixir and Phoenix.

Hope you enjoy it!

Thanks for the help! I didn’t quite catch the nuance in the examples that the schema.ex file needed to import the top level Absinthe.Schema.

I think the functional aspect of the language is pretty natural for me. However there are some definite quirks - for example, Absinthe’s autoconversion of field names from camel case to snake case definitely got me for a bit. But this has definitely been a fun exploration!

Again, I really appreciate your time and assistance!