Skip to content

Instantly share code, notes, and snippets.

@tirumaraiselvan
Last active July 31, 2023 17:05
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save tirumaraiselvan/65c6fa80542994ed6ad06fa87a443364 to your computer and use it in GitHub Desktop.
Save tirumaraiselvan/65c6fa80542994ed6ad06fa87a443364 to your computer and use it in GitHub Desktop.
Mount Hasura on Apollo federated gateway
const { ApolloServer } = require("apollo-server");
const gql = require("graphql-tag");
const fetch = require("node-fetch");
const {
introspectionQuery,
buildClientSchema,
printSchema
} = require("graphql");
const typeDefs = gql`
schema {
query: query_root
}
type _Service {
sdl: String
}
type query_root {
_service: _Service!
}
`;
const hasuraURL = "https://somehasuraurl.com/v1/graphql";
async function getHasuraSchema() {
return await fetch(hasuraURL, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
query: introspectionQuery
})
})
.then(res => res.json())
.then(introspectionJSON => {
delete introspectionJSON.data.__schema.subscriptionType; // apollo-gateway does not support subscriptions as of now and having subscription type throws a wierd error!
return printSchema(buildClientSchema(introspectionJSON.data));
});
}
const resolvers = {
query_root: {
_service: async () => {
var hasuraSchema = await getHasuraSchema();
return { sdl: hasuraSchema };
}
}
};
const schema = new ApolloServer({ typeDefs, resolvers });
schema.listen({ port: process.env.PORT }).then(({ url }) => {
console.log(`schema ready at ${url}`);
});
@tirumaraiselvan
Copy link
Author

tirumaraiselvan commented Oct 10, 2019

This is sample code for a remote schema which adds the _service field to query_root which helps to mount Hasura on Apollo (Federated) Gateway.

@tsaiDavid
Copy link

tsaiDavid commented Nov 5, 2019

@tirumaraiselvan - your note on apollo-gateway not supporting subscriptions, are there any workarounds planned?

PS - thanks for adding this in the first place!

@tirumaraiselvan
Copy link
Author

tirumaraiselvan commented Nov 7, 2019 via email

@matthewmartin0204
Copy link

matthewmartin0204 commented May 5, 2020

This looks great! I'm trying to hook hasura up to gateway using this. In the graphql playground, you can see it brings in the schema as it all the relevant properties are in the docs section. However when I try to query data I get the following error. Any tips? I have replaced some of the fields as I'm doing this for work.

  "errors": [
    {
      "message": "400: Bad Request",
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "response": {
          "url": "http://hasura-federated:9000/graphql",
          "status": 400,
          "statusText": "Bad Request",
          "body": {
            "errors": [
              {
                "message": "Cannot query field \"some_field\" on type \"query_root\".",
                "locations": [
                  {
                    "line": 1,
                    "column": 2
                  }
                ],
                "extensions": {
                  "code": "GRAPHQL_VALIDATION_FAILED",
                  "exception": {
                    "stacktrace": [
                      "GraphQLError: Cannot query field \"some_field\" on type \"query_root\".",
                      "    at Object.Field (/dist/node_modules/graphql/validation/rules/FieldsOnCorrectType.js:53:31)",
                      "    at Object.enter (/dist/node_modules/graphql/language/visitor.js:324:29)",
                      "    at Object.enter (/dist/node_modules/graphql/language/visitor.js:375:25)",
                      "    at visit (/dist/node_modules/graphql/language/visitor.js:242:26)",
                      "    at Object.validate (/dist/node_modules/graphql/validation/validate.js:73:24)",
                      "    at validate (/dist/node_modules/apollo-server-core/dist/requestPipeline.js:213:34)",
                      "    at Object.<anonymous> (/dist/node_modules/apollo-server-core/dist/requestPipeline.js:119:42)",
                      "    at Generator.next (<anonymous>)",
                      "    at fulfilled (/dist/node_modules/apollo-server-core/dist/requestPipeline.js:5:58)",
                      "    at processTicksAndRejections (internal/process/task_queues.js:97:5)"
                    ]
                  }
                }
              }
            ]
          }
        },
        "exception": {
          "stacktrace": [
            "Error: 400: Bad Request",
            "    at RemoteGraphQLDataSource.<anonymous> (/dist/node_modules/@apollo/gateway/dist/datasources/RemoteGraphQLDataSource.js:122:25)",
            "    at Generator.next (<anonymous>)",
            "    at /dist/node_modules/@apollo/gateway/dist/datasources/RemoteGraphQLDataSource.js:8:71",
            "    at new Promise (<anonymous>)",
            "    at __awaiter (/dist/node_modules/@apollo/gateway/dist/datasources/RemoteGraphQLDataSource.js:4:12)",
            "    at RemoteGraphQLDataSource.errorFromResponse (/dist/node_modules/@apollo/gateway/dist/datasources/RemoteGraphQLDataSource.js:112:16)",
            "    at RemoteGraphQLDataSource.<anonymous> (/dist/node_modules/@apollo/gateway/dist/datasources/RemoteGraphQLDataSource.js:85:38)",
            "    at Generator.next (<anonymous>)",
            "    at fulfilled (/dist/node_modules/@apollo/gateway/dist/datasources/RemoteGraphQLDataSource.js:5:58)",
            "    at processTicksAndRejections (internal/process/task_queues.js:97:5)"
          ]
        }
      }
    }
  ],
  "data": null
}

@tirumaraiselvan
Copy link
Author

@manik747 Is Hasura protected via admin secret? If yes, is the Authorization header or x-hasura-admin-secret header passed to Hasura from Apollo gateway?

@darrensapalo
Copy link

darrensapalo commented Jan 17, 2021

Just leaving some notes here on my usage of this gist:

Update introspection query

I am using graphql@^15.4.0. I needed to use getIntrospectionQuery() rather than just importing introspectionQuery from graphql.

const {
  buildClientSchema,
  printSchema,
  getIntrospectionQuery
} = require("graphql");

// ....

async function getHasuraSchema() {
  return await fetch(hasuraURL, {
    method: "POST",
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query: getIntrospectionQuery()
    })
  })

@hyungta
Copy link

hyungta commented Jun 25, 2021

I get this error
Can you give me a hint to work it out?

(node:23754) UnhandledPromiseRejectionWarning: Error: A valid schema couldn't be composed. The following composition errors were found:
[hasura] Mutation -> Found invalid use of default root operation name Mutation. Mutation is disallowed when Schema.mutation is set to a type other than Mutation.
[hasura] Query -> Found invalid use of default root operation name Query. Query is disallowed when Schema.query is set to a type other than Query.
at ApolloGateway.createSchemaFromServiceList (/Users/hbkimz/Documents/works/capa/node_modules/@nestjs/graphql/node_modules/@apollo/gateway/dist/index.js:432:19)
at ApolloGateway.updateByComposition (/Users/hbkimz/Documents/works/capa/node_modules/@nestjs/graphql/node_modules/@apollo/gateway/dist/index.js:303:48)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async ApolloGateway.updateSchema (/Users/hbkimz/Documents/works/capa/node_modules/@nestjs/graphql/node_modules/@apollo/gateway/dist/index.js:279:13)
at async ApolloGateway.loadDynamic (/Users/hbkimz/Documents/works/capa/node_modules/@nestjs/graphql/node_modules/@apollo/gateway/dist/index.js:258:13)
at async ApolloGateway.load (/Users/hbkimz/Documents/works/capa/node_modules/@nestjs/graphql/node_modules/@apollo/gateway/dist/index.js:229:15)
(Use node --trace-warnings ... to show where the warning was created)
(node:23754) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:23754) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment