Unable to use string keys in Absinthe GraphQL lookup

I’ve got a simple Phoenix app using Absinthe pointed at a Mongo database. This does not use Ecto… it’s a more bare-bones use-case.

Mongo returns is BSON documents as maps with string keys, but Absinthe expects its results to use atom keys. Per https://hexdocs.pm/absinthe/Absinthe.Schema.html#replace_default/4 I’ve tried adding the following middleware to my schema.ex:

    def middleware(middleware, field, object) do
      new_middleware = {Absinthe.Middleware.MapGet, to_string(field.identifier)}

      middleware
      |> Absinthe.Schema.replace_default(new_middleware, field, object)
    end

but as soon as I make a query using GraphiQL, I get a bunch of JS errors in the output pane:

assertValidName@https://cdn.jsdelivr.net/npm/graphiql-workspace@1.1.4/graphiql-workspace.min.js:21:12952
e@https://cdn.jsdelivr.net/npm/graphiql-workspace@1.1.4/graphiql-workspace.min.js:20:1831
p@https://cdn.jsdelivr.net/npm/graphiql-workspace@1.1.4/graphiql-workspace.min.js:21:26904
c@https://cdn.jsdelivr.net/npm/graphiql-workspace@1.1.4/graphiql-workspace.min.js:21:26320
i@https://cdn.jsdelivr.net/npm/graphiql-workspace@1.1.4/graphiql-workspace.min.js:21:25554
buildClientSchema/I<@https://cdn.jsdelivr.net/npm/graphiql-workspace@1.1.4/graphiql-workspace.min.js:21:29305
buildClientSchema@https://cdn.jsdelivr.net/npm/graphiql-workspace@1.1.4/graphiql-workspace.min.js:21:29282
value/<@https://cdn.jsdelivr.net/npm/graphiql-workspace@1.1.4/graphiql-workspace.min.js:14:12777

I get the same errors if add my own middleware:

    def middleware([{Absinthe.Middleware.MapGet, _}], %{identifier: field_identifier}, _) do
      [{Absinthe.Middleware.MapGet, Atom.to_string(field_identifier)}]
    end
    def middleware(middleware, _, _), do: middleware

I don’t know if its relevant, but my GraphQL query uses query variables:

query thisTextCouldBeLiterallyAnything ($sourceSpace:String!, $sourceType:String!, $sourceId: String!) {
  content (sourceSpace: $sourceSpace, sourceType: $sourceType, sourceId: $sourceId){
    sourceSpace
    sourceType
    sourceId
    content
  }
}

and query variables:

{
	"sourceType": "some_type",
	"sourceId": "id-123",
	"sourceSpace": "some_source"
}

The only way I’ve gotten this to work is if I manually modify the map keys, but I feel like middleware would be the cleaner solution.

Can anyone help point me to what I’m doing wrong? Thanks!

Elixir 1.9.4 (compiled with Erlang/OTP 22)

Dependency           Current     Latest      Update possible
absinthe             1.4.16      1.4.16
absinthe_plug        1.4.7       1.4.7
phoenix              1.4.11      1.4.11

I can’t see exactly what errors you are seeing but what you could do is replace the middleware with a new middleware that first checks for the atom key, and then for the string key as a fallback. That should cover all situations. Also a solution others have tried

See https://github.com/absinthe-graphql/absinthe/blob/v1.5.0-beta.2/lib/absinthe/middleware/map_get.ex on how to write a middleware.

Hey @fireproofsocks. I think the issue is that def middleware in 1.4 may be allowed to edit the middleware of ALL fields, even introspection fields. This means that changing the default globally to expect strings will break introspection. You can ignore introspection fields by putting the following clauses prior to the one you have:

def middleware(middleware, %{name: "__" <>_}, _), do: middleware
def middleware(middleware, _, %{name: "__" <>_}), do: middleware

I believe this is fixed in 1.5, but I’d have to check.

1 Like

Thanks for the info! I think we’ll wait for 1.5 and refactor our workaround if necessary.

Ah yes, came across the issue dealing with this:

1 Like