Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support gateways without executors #5539

Merged
merged 1 commit into from Jul 23, 2021
Merged

Conversation

glasser
Copy link
Member

@glasser glasser commented Jul 23, 2021

Previously gateways could express their executor in two ways: as the
executor method (required to exist!) and as part of the return value
from load (which was ignored!).

Now we just return it from load, and allow it to be null.

This supports a mocking use case. Fixes #5518. It lets you do something
like:

import { addMocksToSchema } from '@graphql-tools/mock';
const realGateway = new ApolloGateway();
const gateway: GatewayInterface = {
  async load(options) {
    const { schema } = await realGateway.load(options);
    return {
      // this `schema` is actually ignored; the one in onSchemaLoadOrUpdate
      // is what matters. this helps keep the typings working, at least.
      schema: addMocksToSchema({ schema }),
      executor: null,
    };
  },
  stop() {
    return realGateway.stop();
  },
  onSchemaLoadOrUpdate(callback) {
    return realGateway.onSchemaLoadOrUpdate((schemaContext) => {
      callback({
        ...schemaContext,
        apiSchema: addMocksToSchema({ schema: schemaContext.apiSchema, mocks }),
      });
    });
  },
};
const server = new ApolloServer({ gateway });

to define a server that follows a managed federation graph but executes
queries using mocking.

Previously gateways could express their executor in two ways: as the
executor method (required to exist!) and as part of the return value
from load (which was ignored!).

Now we just return it from load, and allow it to be null.

This supports a mocking use case. Fixes #5518. It lets you do something
like:

    import { addMocksToSchema } from '@graphql-tools/mock';
    const realGateway = new ApolloGateway();
    const gateway: GatewayInterface = {
      async load(options) {
        const { schema } = await realGateway.load(options);
        return {
          schema: addMocksToSchema({ schema }),
          executor: null,
        };
      }
      stop() {
        return realGateway.stop();
      }
      onSchemaLoadOrUpdate(callback) {
        return realGateway.onSchemaLoadOrUpdate(callback);
      }
    };
    const server = new ApolloServer({ gateway });

to define a server that follows a managed federation graph but executes
queries using mocking.
@glasser glasser merged commit 5b38dd7 into release-3.1.0 Jul 23, 2021
@glasser glasser deleted the glasser/mock-gateway branch July 23, 2021 05:49
@glasser glasser added this to the MM-2021-07 milestone Jul 23, 2021
@hwillson hwillson removed this from the MM-2021-07 milestone Jul 29, 2021
@setchy
Copy link

setchy commented Jul 31, 2021

Hi @glasser - do you happen to have a complete example you can share?

I've spent quite some time this morning and haven't had any success. I've followed the above fragment you shared, but any queries are still returning null instead of a mocked value (tried both default mocks and custom mocks)

@glasser
Copy link
Member Author

glasser commented Aug 2, 2021

@setchy I'll admit I threw the above together pretty quickly... I'm pretty sure I tested it though! Can you show me a codesandbox or repo demonstrating that it doesn't work with AS 3.1? (FYI I'm on and off vacation the next few weeks.)

@setchy
Copy link

setchy commented Aug 3, 2021

No problems at all @glasser - decent chance its my user error 😅

Here is a stripped down minimal recreation - https://github.com/setchy/apollo-server-3-mocked-federation

Enjoy your vacation! 😎

@glasser
Copy link
Member Author

glasser commented Aug 18, 2021

Ah @setchy, here's what's going on. After some recent refactors (which introduced onSchemaLoadOrUpdate), the schema returned from gateway.load() is mostly ignored (unless you're using an old version of gateway without onSchemaLoadOrUpdate). The actual thing that drives what schema is used by the server is the onSchemaLoadOrUpdate callback. So you still need to call and await realGateway.load in your load, but the schema that matters is coming through onSchemaLoadOrUpdate.

So it looks like this works:

const gateway: GatewayInterface = {
  async load(options) {
    await realGateway.load(options);
    return {
      schema: null,
      executor: null,
    };
  },
  stop() {
    return realGateway.stop();
  },
  onSchemaLoadOrUpdate(callback) {
    return realGateway.onSchemaLoadOrUpdate((schemaContext) => {
      callback({
        ...schemaContext,
        apiSchema: addMocksToSchema({ schema: schemaContext.apiSchema, mocks }),
      });
    });
  },
};

(If returning schema: null here is scary (it probably breaks TypeScript strict mode) you can keep your existing addMockToSchema call; I'm just reasonably sure the schema returned there is ignored if you have the rest set up properly.)

I've updated the PR description to show the new code.

@setchy
Copy link

setchy commented Aug 19, 2021

Awesome, this is working like a treat! Thank you @glasser 👏

I've updated my sample repo with the above, too

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 21, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants