question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Federation] How to merge schema from gateway itself.

See original GitHub issue

In short, is there a way to implement Apollo Federation such that the gateway itself has it’s own schema?

(EDIT) TLDR No, the gateway can’t also be a federated service.

Federating Apollo Server where the gateway itself has a schema

@apollo/gateway@0.6.5 @apollo/federation@0.6.2

Expected Behavior

When I am instantiating my Apollo Gateway server, I expect that I should be able to merge schemas from federated services, as well as the schema from the gateway itself.

Actual Behavior

The gateway server fails to mount the /graphql route because it is expecting all of the services to be currently running before it does so.

On run time, the following error is printed to the console:

POST /graphql 404 11.251 ms - 147
Encountered error when loading gateway at http://localhost:8000/graphql: invalid json response body at http://localhost:8000/graphql reason: Unexpected token < in JSON at position 0
[DEBUG] Fri Jun 07 2019 12:11:07 GMT-0400 (Eastern Daylight Time) apollo-gateway: Configuration loaded for Gateway
[DEBUG] Fri Jun 07 2019 12:11:07 GMT-0400 (Eastern Daylight Time) apollo-gateway: Composing schema from service list:
  remote-svc
TypeError: schema.toConfig is not a function
    at Object.composeServices (/gateway-app/node_modules/@apollo/federation/dist/composition/compose.js:191:67)
    at Object.composeAndValidate (/gateway-app/node_modules/@apollo/federation/dist/composition/composeAndValidate.js:13:41)
    at ApolloGateway.createSchema (/gateway-app/node_modules/@apollo/gateway/dist/index.js:90:47)
    at ApolloGateway.<anonymous> (/gateway-app/node_modules/@apollo/gateway/dist/index.js:81:22)
    at Generator.next (<anonymous>)
    at fulfilled (/gateway-app/node_modules/@apollo/gateway/dist/index.js:4:58)
    at process._tickCallback (internal/process/next_tick.js:68:7)

Source Code

const url = new URL(`redis://${REDIS_URL}:${REDIS_PORT}/${REDIS_DATABASE}`).toString()

const cache = new RedisCache({ url })

const context = ({ req }) => {
  if (!(req.user || req.headers.authorization === ROUTE_AUTH)) {
    throw new AuthenticationError('Not authenticated')
  }
  return { user: req.user, req: req }
}

try {
  const loadGateway = async () => {
    try {
      const { schema, executor } = await gateway.load()
      return { schema, executor }
    } catch (err) {
      console.error(err)
      return null
    }
  }

  const gateway = new ApolloGateway({
    debug: process.env.ENV !== 'prod',
    serviceList: [
      { name: 'gateway', url: `${GATEWAY_HOSTNAME}/graphql` },
      { name: 'remote-svc', url: `${REMOTE_SERVICE_HOSTNAME}/graphql` },
    ],
  })

  const { schema, executor } = loadGateway()
  const server = new ApolloServer({
    schema,
    executor,
    cache,
    dataSources,
    engine: { apiKey: ENGINE_API_KEY },
    tracing: true,
    context,
  })
  server.applyMiddleware({ app })
} catch (err) {
  console.error(err)
}

Justification

The reason for implementing our gateway server this way is to primarily for ease of authentication.

Our gateway server performs all authentication so that we do not have to expend an unnecessary round trip to authenticate a user before executing their request.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

5reactions
hnq90commented, Oct 8, 2019

After migration from Schema Stitching to Federation, we tried several ways to keep the Gateway keeps its own schema. We couldn’t separate the schema away the Gateway for some reasons. Finally, we have to start 2 GraphQL server in same server with different port and path. The Federation GraphQL server must be run before Gateway GraphQL server started.

  • Federation GraphQL Server: /graphq-extended on port 3001.
  • Apollo Gateway Server: /graphql on port 3000.

We haven’t found any better solution but currently it works 🥇 🔥

Here’s the implementation:

export async function runFederationServer({ PORT: portFromEnv = DEFAULT_PORT }) {
  const path = '/graphql-extended'
  const app: express.Application = express()
  // ...
  const serviceSchema = buildFederatedSchema(gatewaySchema.schemas)
  const server = new ApolloServer({
    schema: serviceSchema,
    context: ({ req, res }) => { /* */ }
  })
  
  return app
}

export async function runServer({ PORT: portFromEnv = DEFAULT_PORT, GRAPHQL_ENDPOINTS: graphqlEndpoints = '' } = {}) {
  const path = '/graphql'
  const app: express.Application = express()
  // ...
  const serviceList = [
   {
     name: 'Extended Schema',
     uri: 'http://0.0.0.0:3001/graphql-extended',
   },
   {
     // Other Federation GraphQL servers
   },
  ]
  const gateway = new ApolloGateway({
    serviceList,
    buildService({ url }) { /* */ }
  })
  
  return app
}

runFederationServer(process.env).then(runServer(process.env))
2reactions
calebfarukicommented, Jun 9, 2019

I’ll jump to a conclusion here based on the naming of your service: are you trying to run the gateway at port 8000 and treat it as a federated service at the same time? If so, that’s not going to work; the gateway has to resolve all schemas before it can compose the final schema.

Exactly that.

Okay, so the solution here is to move the schema from the gateway server to another service.

Thanks for confirming that!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Migrating from schema stitching - Apollo GraphQL Docs
Step 4: Move linking logic to your subgraphs. When using a schema-stitching gateway, your linking logic typically resides in the gateway itself. In...
Read more >
Getting Started with Apollo Federation and Gateway
Each service will have a federated schema, and we will merge those two schemas into the gateway-level API so that clients can query...
Read more >
To Federate or Stitch a GraphQL gateway, revisited
Types with the same name are merged together in the gateway. Type merging encourages sub-service schemas to be independently valid.
Read more >
Schema Stitching & Federation: Not the Best Solutions for ...
The diagram below shows how the two compare when you create a gateway or data layer to combine different GraphQL services. StepZen vs....
Read more >
Migrating from schema stitching - Apollo Server - Netlify
When using a schema-stitching gateway, your linking logic typically resides in the gateway itself. In the federation model, however, linking logic resides in ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found