Search code examples
javagraphqlapollo-federationapollo-gateway

Resolver Issue for @extends Type in GraphQL Apollo Federation-JVM


I am quite new to Apollo Federation and Gateway and trying to use apollo federation-jvm for a demo project. I have created two federated services using federation jvm. Both these services are connected to each other via Apollo Gateway. Using this node gateway example from their official github page.

Below is the schema and resolvers for these services:

Federated Service 1:

video.graphql

type Video @key(fields: "videoId") {
    videoId: String!
    description: String
    relatedNameId: String
}

type Query {
    topVideo: Video
    allVideos: [Video]
}

Resolvers for video.graphql

@Service
public class VideoQuery implements GraphQLQueryResolver {

    private static final List<Video> videos = Lists.newArrayList(
            Video.builder().videoId("vi00000001").description("Video 1").relatedNameId("nm000001").build(),
            Video.builder().videoId("vi00000002").description("Video 2").relatedNameId("nm000001").build()
    );

    public Video topVideo() {
        return videos.get(0);
    }

    public List<Video> allVideos() {
        return videos;
    }
}

Federated service 2:

name.graphql

type Name @key(fields: "nameId") {
    nameId: String!
    displayName: String
}

type Query {
    getByNameId(nameId: String): Name
    getAllNames: [Name]
}

Resolvers for name.graphql

@Service
public class NameQuery implements GraphQLQueryResolver {

    private static final List<Name> names = Lists.newArrayList(
            Name.builder().nameId("nm0000001").displayName("Pam Beesley").build(),
            Name.builder().nameId("nm0000002").displayName("Dwight Schrute").build(),
            Name.builder().nameId("nm0000003").displayName("Michael Scott").build()
    );

    public Name getByNameId(final String nameId) {
        final Optional<Name> oName = names.stream().filter(name -> name.getNameId().equalsIgnoreCase(nameId))
                                     .findFirst();
        return oName.orElse(null);
    }

    public List<Name> getAllNames(final DataFetchingEnvironment dataFetchingEnvironment) {
        return names;
    }

}

I am able to call all the API's (topVideo, allVideos, getByNameId, getAllNames) in Type Query of both the services via gateway without any issues.

However when I extend the Name Type in Video Type schema by adding the following to the video.graphql schema

type Name @key(fields: "nameId") @extends {
    nameId: String! @external
    getVideoByNameId: [Video]
}

I am not sure how to write the resolver for getVideoByNameId field.

I have tried adding method getVideoByNameId(String nameId) to VideoQuery.java (returning hardcoded video object from getVideoByNameId method) but the graph always returns null.

I have also tried to create RuntimeWiring using below code and then passing that when creating GraphQLSchema object as shown in an example on their github page

private static RuntimeWiring getRuntimeWiring(){
        return RuntimeWiring.newRuntimeWiring()
                            .type(newTypeWiring("Name")
                                                  .dataFetcher("getVideoByNameId", new StaticDataFetcher(someVideo)))
                            .type(newTypeWiring("Query")
                                                  .dataFetcher("topVideo", new StaticDataFetcher(someVideo)))
                            .type(newTypeWiring("Query")
                                                  .dataFetcher("allVideos", new StaticDataFetcher(someVideo)))
                            .build();
    }

Nothing seems to work. Any help is highly appreciated.


Solution

  • You'll need to implement fetchEntities and resolveEntityType for your Name type similarly to the way they are implemented here.