ardatan / graphql-mesh

🕸️ GraphQL Federation Framework for any API services such as REST, OpenAPI, Swagger, SOAP, gRPC and more...

Home Page:https://the-guild.dev/graphql/mesh

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

The Hive integration does not support schema stitched projects where multiple services contribute to the final graph

dpnova opened this issue · comments

cc @kamilkisiela

Issue workflow progress

Progress of the issue based on the
Contributor Workflow

Make sure to fork this template and run yarn generate in the terminal.

Please make sure Mesh package versions under package.json matches yours.

  • 2. A failing test has been provided
  • 3. A local solution has been provided
  • 4. A pull request is pending review

Describe the bug

Having multiple handlers all using the same hive schema source results in mesh thinking that all fields exist on all subgraph services:

sources:
  - name: datasets
    handler:
      graphql:
        source: ${BACKEND_GRAPH_SOURCE}
        subscriptionsProtocol: SSE
        schemaHeaders:
          X-Hive-CDN-Key: ${BACKEND_GRAPH_HIVE_CDN_KEY}
        endpoint: ${DATASETS_API}
  - name: calculations
    handler:
      graphql:
        source: ${BACKEND_GRAPH_SOURCE}
        subscriptionsProtocol: SSE
        schemaHeaders:
          X-Hive-CDN-Key: ${BACKEND_GRAPH_HIVE_CDN_KEY}
        endpoint: ${CALCULATIONS_API}

This would be avoided by having mesh be able to fetch an individual service's schema - potentially from the services artefact type documented here

One solution of course, is to split each subgraph into a separate Hive project, but that defeats the purpose of using a stitched project in Hive.

To Reproduce Steps to reproduce the behavior:

Expected behavior

Environment:

  • OS:
  • @graphql-mesh/...:
  • NodeJS:

Additional context

Unfortunately the current version of Mesh doesn't have an integration like you described. Each source needs to be a seperate Hive project, and merged/composed by Mesh CLI's build command not by Hive.
We call this version of Mesh v0.
However you can check incoming release-candidate Mesh v1 that has a different approach similar to what you asked for;
https://the-guild.dev/graphql/mesh/v1
But that newer version of Mesh uses Federation instead of "Stitching".

Unfortunately the current version of Mesh doesn't have an integration like you described. Each source needs to be a seperate Hive project, and merged/composed by Mesh CLI's build command not by Hive. We call this version of Mesh v0. However you can check incoming release-candidate Mesh v1 that has a different approach similar to what you asked for; https://the-guild.dev/graphql/mesh/v1 But that newer version of Mesh uses Federation instead of "Stitching".

Ah - when I spoke to @Urigo about this he was all about the new stitching. Are we moving from it to prefer federation now? Is there a place where the current "best practice" thoughts from the guild are?

I always liked that stitching didn't force subgraphs to know about how they are federated. Or has federation improved on this front now?

I always liked the type merging approach 🤔

One thought I mentioned in a support ticket to hive was to have separate CDN links for each subservice in a stitched graph.

Edit: nm I saw the reply over there.

This will be a new mesh project, it seems like we should roll forward to the v1 approach.

I need to do some reading.

FYI @kamilkisiela Our workaround for now is to download the services cdn object and write schema files locally before we mesh build.

@dpnova the approach that @ardatan is talking about with v1 (which we recommend you try, if you need help, we can connect our teams together through Slack and we can answer any questions you might have)
is federation approach with stitching as the implementation itself (it fully supports federation)
You can still use the current approach
The main thing you will miss is the static analysis that makes sure all graphs are connecting in a predictable way and also a supergraph that makes sure execution is more predictable
The state of the art would be the Mesh v1 docs which we are currently working on to get it ready for the release, so any thing that you think is missing there please let us know and we'll add it!

thanks @Urigo ! Right now we depend on additionalResolvers pretty heavily to force visiting every instance of a particular Query.foo and Subscription.foo that is defined on multiple backend services - if we can continue to do that with V1 we should be fine. I'll do a blog post about our sync engine and how it's powered by mesh soon 👍

Given this is a wontfix, I'll include our workaround here for anyone else in the same situation. We run this before mesh build, and have the meshrc refer to the local file paths for each handler source.

import fs from 'fs'
import path from 'path'

const CDN_URL = process.env.BACKEND_GRAPH_SERVICE_SOURCE ?? ''
const CDN_KEY = process.env.BACKEND_GRAPH_HIVE_CDN_KEY ?? ''

async function downloadSchemas() {
  const requestOptions = {
    method: 'GET',
    headers: {
      'X-Hive-CDN-Key': CDN_KEY,
      redirect: 'follow',
    },
  }

  try {
    console.debug('Downloading from CDN', CDN_URL)
    const response = await fetch(CDN_URL, requestOptions)
    if (!response.ok) {
      throw new Error(`Failed to fetch schemas: ${response.statusText}`)
    }
    const services = await response.json()

    for (const service of services) {
      const { name, sdl, url } = service
      const filePath = path.join(__dirname, `/../schemas/${name}.graphql`)
      const fileContent = `${sdl}


      `

      fs.writeFileSync(filePath, fileContent, 'utf8')
    }
  } catch (error) {
    console.error(`Error downloading schemas: ${error.message}`)
    throw error
  }
}

downloadSchemas()