apollographql/apollo-server

@apollo/gateway doesn't work with apollo-server-lambda since 0.9.0

nihalgonsalves opened this issue ยท 11 comments

  • Package: @apollo/gateway
  • Version: since v0.9.0
  • Last known working version: v0.8.2

The server crashes with "Error: Expected undefined to be a GraphQL schema" when using new gateway version with apollo-server-lambda.

If you call gateway.load() manually and pass the schema and executor to the ApolloServer constructor, you get "Error: Apollo Server requires either an existing schema, modules or typeDefs"

Here's a minimal reproducible example:

import { ApolloServer } from 'apollo-server-lambda';
import { ApolloGateway } from '@apollo/gateway';

const gateway = new ApolloGateway({
  serviceList: [
    { name: 'service-a', url: 'http://localhost:4001' },
  ],
});

const server = new ApolloServer({
  gateway,
  introspection: true,
  playground: true,
  subscriptions: false,
  context: ({ event, context }) => ({
    headers: event.headers,
    functionName: context.functionName,
    event,
    context,
  }),
});

exports.graphqlHandler = server.createHandler({
  cors: {
    origin: '*',
    credentials: true,
    methods: 'GET, POST',
    allowedHeaders: 'Origin, X-Requested-With, Content-Type, Accept, Authorization',
  },
});

Here's what changed between the versions: b0a9ce0...99f78c6 (from a preliminary look gateway.load() seems to be the change that causes the issue).

Reproducible repository here: https://github.com/nihalgonsalves/apollo-server-issue3190

Run yarn run-service first and then run separately yarn run-gateway. On master, this should work:

curl -d '{"query":"{ hello }"}' -H "Content-Type: application/json" -X POST http://localhost:3000/graphql

> {"data":{"hello":"world"}}

On the other branches (gateway-@-0.9.0 & gateway-@-0.9.1), it should fail, on the second request:

{"errors":[{"message":"Invalid options provided to ApolloServer: Expected undefined to be a GraphQL schema.","extensions":{"code":"INTERNAL_SERVER_ERROR","exception":{"stacktrace":["Error: Invalid options provided to ApolloServer: Expected undefined to be a GraphQL schema.","    at assertSchema ... <stack trace redacted>

You can also go to http://localhost:3000/graphql in a browser to see the same error.

This is the exact problem I'm facing as well!

@nihalgonsalves thank you for the great issue report and reproduction. I've confirmed the bug (and also confirmed it doesn't happen for apollo-server-express).

I'll get back to this issue with an update within the week - I'll need to do some digging and probably pick @abernix 's brain in order to understand what might be going on here, as I'm wholly unfamiliar with lambda. In the meantime, any results of further debugging on your end would be welcomed!

Update: I had originally thought I had a similar issue, albeit in the context of Azure Function, not AWS Lambda. Note that the cause in my case simply was using the wrong URLs for the federated services. For those ending up here for the Azure issue: Use routePrefix in host.json or double-check that the URLs you pass to Apollo Gateway match the URLs of your GraphQL endpoints.

In my Azure Function setup, passing the wrong URL to the gateway, I am getting the same issue, testing on localhost.

My function script was using Apollo Gateway (0.10.4) like this, with no path to the API (just localhost:7071).

const gateway = new ApolloGateway({
    serviceList: [
        { name: 'YetAnotherAPI', url: 'http://localhost:7071' },
    ]
});

const server = new ApolloServer({
  gateway, subscriptions: false, playground: true, introspection: true
});

  
exports.graphqlHandler = server.createHandler();

During startup, my Azure Function complained:

[29/8/19 6:34:45 am] (node:17465) UnhandledPromiseRejectionWarning: Error: Expected undefined to be a GraphQL schema.
[29/8/19 6:34:45 am]     at assertSchema (webpack:///./node_modules/graphql/type/schema.mjs?:37:11)
[29/8/19 6:34:45 am]     at validateSchema (webpack:///./node_modules/graphql/type/validate.mjs?:38:64)
[29/8/19 6:34:45 am]     at assertValidSchema (webpack:///./node_modules/graphql/type/validate.mjs?:61:16)
[29/8/19 6:34:45 am]     at assertValidExecutionArguments (webpack:///./node_modules/graphql/execution/execute.mjs?:157:76)
[29/8/19 6:34:45 am]     at executeImpl (webpack:///./node_modules/graphql/execution/execute.mjs?:107:3)
[29/8/19 6:34:45 am]     at Module.execute (webpack:///./node_modules/graphql/execution/execute.mjs?:85:63)
[29/8/19 6:34:45 am]     at Object.generateSchemaHash (webpack:///./node_modules/apollo-server-core/dist/utils/schemaHash.js?:14:32)
[29/8/19 6:34:45 am]     at ApolloServer.generateSchemaDerivedData (webpack:///./node_modules/apollo-server-core/dist/ApolloServer.js?:281:41)
[29/8/19 6:34:45 am]     at ApolloServerBase.schemaDerivedData._schema.then.schema (webpack:///./node_modules/apollo-server-core/dist/ApolloServer.js?:208:66)
[29/8/19 6:34:45 am]     at <anonymous>

My fix was to correct the API URL by specifying

{
    "version": "2.0",
    "extensions": {
        "http": {
            "routePrefix": ""
        }
    },
    "watchDirectories": [
        "dist"
    ]
}

Alternatively, I could just have specified the path to the API as http://localhost:7071/path-to-api.

I have tried Nihal's repo to see if the issue is also URL-related but I couldn't find a similarly simple fix. Next I've tried Apollo Gateway 0.9.1 with my Azure Function setup but I don't have the same issue there... if the URLs are correct. I hope this information is useful for someone anyway.

@trevor-scheer Any updates on this issue?

I'm running into this error as well, although it's tied to using the Graph Manager (i.e. no serviceList) with serverless-offline

@nihalgonsalves I cloned your repo and saw the reproduction. After hitting that error, I upgraded federation and gateway and things started working again:

   "dependencies": {
-    "@apollo/federation": "^0.8.0",
-    "@apollo/gateway": "^0.9.0",
+    "@apollo/federation": "^0.10.2",
+    "@apollo/gateway": "^0.10.7",
     "apollo-server": "^2.8.2",
     "apollo-server-lambda": "^2.8.2",
     "graphql": "^14.5.0"

@nathanchapman Thanks. It does work now, so I will close this issue.

We ended up running it in a container instead, because it seems like the gateway isn't really designed for the lambda execution model (fetching schema updates, caching, eventually: subscriptions, etc). Even if it's being fetched from the Graph Manager, every new concurrent execution will incur a cold start penalty of loading the schema.

@trevor-scheer would it make sense to document that the gateway is not intended to be run in a Lambda environment (and other FaaS envs)?

@nathanchapman were you able to solve your serverless-offline issue in managed mode? I'm running into the same problem.

It does work with AWS SAM, but am curious if there's a solution using serverless-offline as well.

@cluedtke Nope, no luck yet ๐Ÿ˜ž
Here's the issue: #3416

@nihalgonsalves did you find a way to make this work on Lambda? I'd love to push forward with that approach by rendering remote schemas to a file during a build step or something similar but haven't found any references for doing so.

@cazzer We didn't spend any more time on it and just used a regular container on Fargate ECS. I suspect that it would be technically feasible to do what you propose, but it wouldn't really fit in with the decentralised approach of deploying federated services separately and registering them with Graph Manager.

Every time a team wants to deploy, they'd have to trigger the Lambda build and make sure that's okay as well. Or if you use Graph Manager and somehow poll for changes to re-build your Lambda, the team still has to make sure that it succeeded, etc.