GraphQL - resolve JSON as array of graphql types to support batch querying

364 views Asked by At

I've got a collection of graphql services that are combined together in a gateway using graphql-tools schema stitching.

Here's some sample code for reference:

async function makeGatewaySchema() {
  // define the remote executors, introspect the subschemas, etc.
  return stitchSchemas({
    subschemas: [
      {
        schema: postSubschema,
        executor: postExecutor,
        batch: true,
      },
      {
        schema: userSubschema,
        executor: userExecutor,
        batch: true,
      },
    ],
    typeDefs: `
    ...
    extend type User {
      posts: [Post]
      batchPostsJSON: JSON
      batchPosts: [Post]
    }
    ...
  `,
    resolvers: {
      User: {
        posts: {
          selectionSet: "{ id }",
          resolve(user, args, context, info) {
            return delegateToSchema({
              schema: schemaPost,
              operation: "query",
              fieldName: "postsByUserId",
              args: { id: user.id },
              context,
              info,
            });
          },
        },
        batchPostsJSON: {
          selectionSet: "{ id }",
          resolve(user, args, context, info) {
            return batchDelegateToSchema({
              schema: schemaFavorite,
              operation: "query",
              fieldName: "postsByUserIds",
              key: user.id,
              argsFromKeys: (ids) => ({ ids }),
              valuesFromResults: (results, keys) => {
                return keys.map((id) => {
                  return results.filter((f) => f.user_id === id);
                });
              },
              context,
              info,
            });
          },
        },
        batchPosts: {
          selectionSet: "{ id }",
          resolve(user, args, context, info) {
            return batchDelegateToSchema({
              schema: schemaPost,
              operation: "query",
              fieldName: "postsByUserIds",
              key: user.id,
              argsFromKeys: (ids) => ({ ids }),
              valuesFromResults: (results, keys) => {
                // doesn't matter, we don't get here
              },
              context,
              info,
            });
          },
        },
      },
    },
  });
}

In the example code above, I have three ways to get posts associated with a user:

1: User.posts

This works fine but isn't batched

2: User.batchPostsJSON

This is batched very nicely and works perfectly with one problem: the JSON return type doesn't allow me to query Post fields - I just get all of them no matter what. Worse, if Post was related to some third type, I wouldn't be able to follow that relationship.

3: User.batchPosts

This allows me to query fields of Post, but throws an exception - I've defined the return type as array of Post, but JSON is what comes back and I get an error in the gateway.

Is there a way to handle the JSON returned by the subschema and pretend that I'm really getting [Post] back instead? By the time my valueFromResults is finished, that IS what it will look like. The problem is that the return type mismatch between my typedef and the actual resolver throws an error before I have the chance to reformat the return value.

0

There are 0 answers