graphql-modules icon indicating copy to clipboard operation
graphql-modules copied to clipboard

Apollo 4 support

Open dev-mich opened this issue 2 years ago • 9 comments

Is your feature request related to a problem? Please describe.

Hi guys, is there any plan to support the latest apollo server version 4?

tried this morning to have things working with @apollo/server 4.0.1 and graphql-modules 2.1.0 with no luck

dev-mich avatar Oct 18 '22 09:10 dev-mich

createSchemaForApollo is marked as deprecated but it works for me. It would still be nice to know what the 'official' / intended solution might be.

Example code:

const application = createApplication({
  modules: [echoModule]
});

const server = new ApolloServer(
  {
    schema: application.createSchemaForApollo()
  });

To elaborate on a specific problem I bumped into:

The Apollo Server 4 migration instructions suggest that gateway can be used where custom executors were previously passed to the constructor.

It's not enough to work by itself though and the Apollo Server type definitions forbid passing more than gateway.

lewisgj avatar Dec 22 '22 13:12 lewisgj

Then it should work like;

const application = createApplication({
  modules: [echoModule]
});
new ApolloServer({
  gateway: {
    async load() {
      return { executor: application.createApolloExecutor() };
    },
    onSchemaLoadOrUpdate() {
      return () => {};
    },
    async stop() {},
  },
});

ardatan avatar Dec 22 '22 13:12 ardatan

I agree - that's what I expected to work, but it didn't in practice. Here's my minimal example - hopefully it's reproducible enough! https://github.com/lewisgj/graphql-modules-apollo-4

lewisgj avatar Dec 22 '22 14:12 lewisgj

Could you try the following code;

const server = new ApolloServer({
    // schema: application.createSchemaForApollo() // graphql-modules has marked this deprecated, but works with Apollo Server 4.
    // Recommended approach is to use gateway:
    gateway: {
        async load() {
            return { executor: application.createApolloExecutor() };
        },
        onSchemaLoadOrUpdate(callback) {
            callback({ apiSchema: application.schema } as any);
            return () => {};
        },
        async stop() {},
    },
});

ardatan avatar Dec 26 '22 08:12 ardatan

This does work, thanks - I try to write Typescript as strict as possible so it's not 100% ideal to have any there, but it'd be enough for me to link back to this issue as justification for either approach I think.

Without the any I get:

TS2345: Argument of type '{ apiSchema: GraphQLSchema; }' is not assignable to parameter of type '{ apiSchema: GraphQLSchema; coreSupergraphSdl: string; }'.   Property 'coreSupergraphSdl' is missing in type '{ apiSchema: GraphQLSchema; }' but required in type '{ apiSchema: GraphQLSchema; coreSupergraphSdl: string; }

but I guess it's more of a question for Apollo and what that field is supposed to do / whether the typing should be as strict.

lewisgj avatar Dec 29 '22 10:12 lewisgj

@ardatan I had to drill into the source code to get understand that Gateway Interface.

Thanks for that.

amochuko avatar Jan 10 '23 14:01 amochuko

It seems like there is still an issue, the apollo-server error functions do not like something about the gateway config setup.

Here is my code:

const server = new ApolloServer({
      // See this issue for more info on this solution: https://github.com/Urigo/graphql-modules/issues/2270
      // schema: application.createSchemaForApollo() // graphql-modules has marked this deprecated, but works with Apollo Server 4.
      // Recommended approach is to use gateway:
      gateway: {
        async load() {
          return { executor: moduleApp.createApolloExecutor() }
        },
        onSchemaLoadOrUpdate(callback) {
          const apiSchema = { apiSchema: moduleApp.schema } as any
          callback(apiSchema)
          return () => {}
        },
        async stop() {}
      },
      formatError: (formattedError: GraphQLFormattedError, error: any) => {
        console.log('FORMATTED ERROR -----> ', formattedError)
        console.log('ERROR -----> ', error)
        return formattedError
      }      
})

await server.start()

app.use(`${basePath}/graphql`, expressMiddleware(server))

It never seems to make it to the formatError function before blowing up when an error occurs. With the above setup you can simply query for a field that does not exist to generate the below errors...

I receive the following errors:

Unexpected error processing request: TypeError: Cannot assign to read only property 'name' of object 'GraphQLError

Followed by:

TypeError: Cannot read property 'code' of undefined
    at enrichError (/node_modules/@apollo/server/dist/cjs/errorNormalize.js:34:43)
    at /node_modules/@apollo/server/dist/cjs/errorNormalize.js:19:28
    at Array.map (<anonymous>)
    at normalizeAndFormatErrors (/node_modules/@apollo/server/dist/cjs/errorNormalize.js:13:33)
    at ApolloServer.errorResponse (/node_modules/@apollo/server/dist/cjs/ApolloServer.js:542:102)
    at ApolloServer.executeHTTPGraphQLRequest (node_modules/@apollo/server/dist/cjs/ApolloServer.js:538:25)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
^[[1;2C

any ideas?

ajzozakiewicz avatar Jan 11 '23 14:01 ajzozakiewicz

We would love to accept a PR to fix that, thank you!

Urigo avatar Feb 06 '23 14:02 Urigo

Could you try the following code;

const server = new ApolloServer({
    // schema: application.createSchemaForApollo() // graphql-modules has marked this deprecated, but works with Apollo Server 4.
    // Recommended approach is to use gateway:
    gateway: {
        async load() {
            return { executor: application.createApolloExecutor() };
        },
        onSchemaLoadOrUpdate(callback) {
            callback({ apiSchema: application.schema } as any);
            return () => {};
        },
        async stop() {},
    },
});

This works for Queries and Mutations. But I'm still getting this error when trying subscriptions

"Cannot read properties of undefined (reading 'ɵgetModuleContext')"

any help with implementing subscriptions with this gateway implementation.

MatamandoKalilani avatar Feb 26 '23 21:02 MatamandoKalilani