Repository: mcollina/fastify-gql
Pull request #218 (2020-07-16 19:42:51)

fix operationName schema type
Respecting the GraphQL spec the operationName can be `null`.

https://spec.graphql.org/October2016/#GetOperation()

This error caused that when executing unnamed operations and the client sends the request with operationName = null, the servers responds:

```
{
  "error": {
    "errors": [
      {
        "message": "Unknown operation named \"\"."
      }
    ],
    "data": null
  }
}
```

PabloSzx: For the test added, if you remove 'null' from the schema, it doesn't pass

![WindowsTerminal_EAlrZ7hSIv](https://user-images.githubusercontent.com/8672915/87807580-69596480-c826-11ea-9a3d-312bd18ad5dd.png)

Patch:
diff --git a/index.d.ts b/index.d.ts
index 9b2a954..4b53dc3 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -3,10 +3,6 @@ import {
   FastifyReply,
   FastifyRequest,
   FastifyInstance,
-  RawServerBase,
-  RawRequestDefaultExpression,
-  RawReplyDefaultExpression,
-  FastifyPlugin,
 } from "fastify";
 import {
   DocumentNode,
@@ -67,7 +63,19 @@ interface QueryRequest {
   extensions?: object;
 }
 
-export interface FastifyGQLOptions {
+export interface FastifyGQLGatewayOptions {
+  /**
+   * A list of GraphQL services to be combined into the gateway schema
+   */
+  gateway: {
+    services: Array<{
+      name: string;
+      url: string;
+    }>;
+  };
+}
+
+export interface FastifyGQLSchemaOptions {
   /**
    * The GraphQL schema. String schema will be parsed
    */
@@ -75,7 +83,7 @@ export interface FastifyGQLOptions {
   /**
    * Object with resolver functions
    */
-  resolvers: IResolvers;
+  resolvers?: IResolvers;
   /**
    * Object with data loader functions
    */
@@ -92,6 +100,9 @@ export interface FastifyGQLOptions {
       ) => any;
     };
   };
+}
+
+export interface FastifyGQLCommonOptions {
   /**
    * Serve GraphiQL on /graphiql if true or 'graphiql', or GraphQL IDE on /playground if 'playground' and if routes is true
    */
@@ -171,15 +182,6 @@ export interface FastifyGQLOptions {
    * Enable federation metadata support so the service can be deployed behind an Apollo Gateway
    */
   federationMetadata?: boolean;
-  /**
-   * A list of GraphQL services to be combined into the gateway schema
-   */
-  gateway?: {
-    services: Array<{
-      name: string;
-      url: string;
-    }>;
-  };
   /**
    * Persisted queries, overrides persistedQueryProvider.
    */
@@ -201,6 +203,7 @@ export interface FastifyGQLOptions {
   allowBatchedQueries?: boolean;
 }
 
+export type FastifyGQLOptions = FastifyGQLCommonOptions & (FastifyGQLGatewayOptions | FastifyGQLSchemaOptions)
 
 declare function fastifyGQL 
   (
diff --git a/lib/routes.js b/lib/routes.js
index 293e703..8b14a1f 100644
--- a/lib/routes.js
+++ b/lib/routes.js
@@ -53,7 +53,7 @@ const requestProperties = {
     type: 'boolean'
   },
   operationName: {
-    type: 'string'
+    type: ['string', 'null']
   }
 }
 


Test patch:
diff --git a/test/routes.js b/test/routes.js
index 749d0c4..d1d0b94 100644
--- a/test/routes.js
+++ b/test/routes.js
@@ -1613,3 +1613,43 @@ test('if ide is graphiql, serve config.js with the correct endpoint', async (t)
   t.strictEqual(res.headers['content-type'], 'application/javascript')
   t.matchSnapshot(res.body)
 })
+
+test('if operationName is null, it should work fine', async (t) => {
+  const app = Fastify()
+  const schema = `
+    type Query {
+      add(x: Int, y: Int): Int
+    }
+  `
+
+  const resolvers = {
+    add: ({ x, y }) => x + y
+  }
+
+  app.register(GQL, {
+    schema,
+    resolvers
+  })
+
+  const operationName = null
+
+  const query = 'query { add(x: 2, y: 3) }'
+
+  const res = await app.inject({
+    method: 'POST',
+    headers: { 'content-type': 'application/json' },
+    url: '/graphql',
+    body: JSON.stringify({
+      query,
+      operationName,
+      variables: {}
+    })
+  })
+
+  t.strictEqual(res.statusCode, 200)
+  t.deepEqual(JSON.parse(res.body), {
+    data: {
+      add: 5
+    }
+  })
+})
diff --git a/test/types/index.ts b/test/types/index.ts
index 8e7f1e5..c34f022 100644
--- a/test/types/index.ts
+++ b/test/types/index.ts
@@ -3,6 +3,7 @@ import Fastify from 'fastify'
 import fastifyGQL, { FastifyGQLOptions } from '../..'
 // eslint-disable-next-line no-unused-vars
 import { ValidationContext, ValidationRule } from 'graphql'
+import { makeExecutableSchema } from 'graphql-tools'
 
 const app = Fastify()
 
@@ -124,3 +125,31 @@ makeGraphqlServer({ schema, resolvers })
 makeGraphqlServer({ schema, resolvers, validationRules: [] })
 makeGraphqlServer({ schema, resolvers, validationRules: [customValidationRule] })
 makeGraphqlServer({ schema, resolvers, validationRules: ({ variables, operationName, source }: { source: string, variables?: Record<string, any>, operationName?: string }) => [customValidationRule] })
+
+// Gateway mode
+
+const gateway = Fastify()
+
+gateway.register(fastifyGQL, {
+  gateway: {
+    services: [{
+      name: 'user',
+      url: 'http://localhost:4001/graphql'
+
+    }, {
+      name: 'post',
+      url: 'http://localhost:4002/graphql'
+    }]
+  }
+})
+
+// Executable schema
+
+const executableSchema = makeExecutableSchema({
+  typeDefs: [],
+  resolvers: []
+})
+
+gateway.register(fastifyGQL, {
+  schema: executableSchema
+})