Skip to content

Support gateways without executors#5539

Merged
glasser merged 1 commit intorelease-3.1.0from
glasser/mock-gateway
Jul 23, 2021
Merged

Support gateways without executors#5539
glasser merged 1 commit intorelease-3.1.0from
glasser/mock-gateway

Conversation

@glasser
Copy link
Copy Markdown
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 force-pushed the glasser/mock-gateway branch from dd72998 to 443c2ff Compare July 23, 2021 05:44
@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
Copy Markdown

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
Copy Markdown
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
Copy Markdown

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
Copy Markdown
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
Copy Markdown

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.

3 participants