How to get data from multiple representations

I need to process the following request:

query {
  _entities(representations: [
    {__typename: "Large", id: "1"},
    {__typename: "Middle", id: "2"}]) {
    ... on Middle {
      small(id: "3") {
        id
        name
      }
    }
  }
}

My small-service subgraph:

type Large @key(fields: "id") @extends {
    id: UUID! @external
    middle(id: UUID!): Middle

}

type Middle @key(fields: "id") @extends {
    id: UUID! @external
    small(id: UUID!): Small
}

type Small @key(fields: "id") {
    id: UUID!
    name: String!
}

SmallController:

@SchemaMapping(typeName = "Middle", field = "small")
public Response small(@Argument UUID id,
                                   Large large,
                                   Middle middle) {
    return smallService.do(id, large, middle);
}

Source builder:

public GraphQlSourceBuilderCustomizer federationTransform() {
        DataFetcher<?> entityDataFetcher = env -> {
            List<Map<UUID, Object>> representations = env.getArgument(_Entity.argumentName);
            return representations.stream()
                    .map(representation -> {
                        if (LARGE.equals(representation.get("__typename"))) {
                            return new Large(UUID.fromString((String) representation.get("id")));
                        }
                        if (MIDDLE.equals(representation.get("__typename"))) {
                            return new MIDDLE(UUID.fromString((String) representation.get("id")));
                        }
                        return null;
                    })
                    .collect(Collectors.toList());
        };
        TypeResolver entityTypeResolver = env -> {
            final Object src = env.getObject();
            if (src instanceof Large) {
                return env.getSchema()
                        .getObjectType(LARGE);
            }
            if (src instanceof Middle) {
                return env.getSchema()
                        .getObjectType(MIDDLE);
            }
            return null;
        };

        return builder -> builder.schemaFactory((registry, wiring) -> Federation.transform(registry, wiring)
                .fetchEntities(entityDataFetcher)
                .resolveEntityType(entityTypeResolver)
                .build());
    }

Error:

Parameter [1] in public Response SmallController.small(java.util.UUID,Large,Middle):  does not match the source Object type 'class Middle'

Notes:

  • With one parameter - all good.
  • On GraphQlSourceBuilderCustomizer level in debug mode I see both representations.

Any advice or help would be greatly appreciated!

Hello :wave:
Its a better question for Spring for GraphQL folks but it looks like you are trying to inject both Middle and Large objects on the @SchemaMapping method which is invalid, i.e. @SchemaMapping allows you to inject parent object (Middle) but it doesn’t know anything about the Large parameter - it is neither an argument nor a parent object so it cannot be resolved.

Thanks,
Derek

My thoughts are that if it is an array, then there is an opportunity to transfer more than one parameter. The question is how to parse them?)

While _entities query does resolve multiple representations, what you are trying to do is very hacky and AFAIK is not something that is handled out of the box.

I’m guessing you probably could hack your way by using DataFetchingEnvironment but again that would be a very hacky solution.

Instead, I’d recommend to revisit your data model and introduce proper relationships.