Skip to content
This repository has been archived by the owner on Sep 11, 2019. It is now read-only.

Add support for schema stitching #2

Closed
jlengstorf opened this issue Nov 1, 2017 · 5 comments
Closed

Add support for schema stitching #2

jlengstorf opened this issue Nov 1, 2017 · 5 comments

Comments

@jlengstorf
Copy link
Member

(Splitting the schema stitching conversation off from the larger discussion in gramps-graphql/gramps-express#39 to help concentrate individual discussions.)

From @ecwyne:

But my sense is that staying as close to the Apollo api will serve GrAMPS well in the long run.

I agree with this 100%. My intention wasn't to suggest that GrAMPS define its own schema stitching API, but rather to suggest that we need to think through how to define the two-way bindings described in the schema stitching docs.

My gut says that the most sustainable way to do this — if we use the User/Chirp example — would be to have the User data source define something like this:

const dataSource = {
  namespace: 'User',
  schema: /* ... */,
  resolvers: /* ... */,
  mocks: /* ... */,
  model: /* ... */,
  stitching: {
    requires: ['Chirp'],
    linkTypeDefs: `
        extend type User {
          chirps: [Chirp]
        }
    `,
    resolvers: mergeInfo => ({
      User: {
        chirps: {
          fragment: `fragment UserFragment on User { id }`,
          resolve(parent, args, context, info) {
            const authorId = parent.id;
            return mergeInfo.delegate(
              'query',
              'chirpsByAuthorId',
              {
                authorId,
              },
              context,
              info,
            );
          },
        },
      },
    },
  }
};

The Chirp schema would be required to define it's own stitching object to enable the author field within the Chirp schema.

The requires field would allow us to check for the existence of required data source(s) before adding the schema stitching pieces to our complete executable schema. (And again, this would be only for local data sources — if stitching with an external data source, that would happen outside of GrAMPS.)

The API above is not necessarily the best way to do this — it's just the first one I thought of. But the main point I'm getting at is the underlying concept: each data source is responsible for stitching its half of the equation.

@ecwyne
Copy link
Collaborator

ecwyne commented Nov 1, 2017

This is very close to the API I would suggest as well, with one exception. We discussed using peerDependencies to declare what a data source "requires".

If we add an additional "Comments" schema to your above example (where a user can see all of their comments)

const dataSource = {
  namespace: 'User',
  schema: /* ... */,
  resolvers: /* ... */,
  mocks: /* ... */,
  model: /* ... */,
  stitching: {
    requires: ['Chirp', 'Comment'],
    linkTypeDefs: `
        extend type User {
          chirps: [Chirp]
          comments: [Comment]
        }
    `,
    resolvers: mergeInfo => ({
      User: {
        comments: {
          fragment: `fragment UserFragment on User { id }`,
          resolve(parent, args, context, info) {
            const authorId = parent.id;
            return mergeInfo.delegate(
              'query',
              'commentssByAuthorId',
              {
                authorId,
              },
              context,
              info,
            );
          },
        },
        chirps: {
          fragment: `fragment UserFragment on User { id }`,
          resolve(parent, args, context, info) {
            const authorId = parent.id;
            return mergeInfo.delegate(
              'query',
              'chirpsByAuthorId',
              {
                authorId,
              },
              context,
              info,
            );
          },
        },
      },
    },
  }
};

What should I do if Chirps is present but not Comments?

peerDependencies would make these requirements all-or-nothing and provide SemVer assurances out of the box.

@jlengstorf
Copy link
Member Author

Oh, shit, I totally forgot about the peerDependencies conversation.

Yes, that's better. Let's do that. 😄

@ecwyne
Copy link
Collaborator

ecwyne commented Nov 2, 2017

@jlengstorf I'm going to take a crack at this today. Do you prefer:

const dataSource = {
  namespace: 'User',
  schema: /* ... */,
  resolvers: /* ... */,
  mocks: /* ... */,
  model: /* ... */,
  stitching: {
    linkTypeDefs: /* ... */,
    resolvers: mergeInfo => /* ... */,
  },
};

or

const dataSource = {
  namespace: 'User',
  schema: /* ... */,
  resolvers: /* ... */,
  mocks: /* ... */,
  model: /* ... */,
  linkTypeDefs: /* ... */,
  stitchResolvers: mergeInfo => /* ... */,
};

@jlengstorf
Copy link
Member Author

Awesome. I think I prefer the first option. It seems clearer to me.

@jlengstorf
Copy link
Member Author

Closed by #12

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants