mercurius icon indicating copy to clipboard operation
mercurius copied to clipboard

¿Is Subscription a reserved type Name?

Open fjmoreno opened this issue 2 years ago • 8 comments

Hi, ¿Is Subscription a reserved type Name? i expect to redefine Subscription rootType name as stated on graphql specs: https://spec.graphql.org/October2021/#sec-Root-Operation-Types

Steps to reproduce

Given following example:

'use strict'

const Fastify = require('fastify')
const mercurius = require('..')

const app = Fastify()

const Series = [{
  name: 'Serie1',
  subPids: ['Sub1','Sub2', 'Sub3']
}, {
  name: 'Serie2',
  subPids: ['Sub1','Sub2']
}, {
  name: 'Serie3',
  subPids: ['Sub1']
}]

const Subscriptions = [
  {
    Pid: 'Sub1',
    Name: 'Subscription1',
  }, {
    Pid: 'Sub2',
    Name: 'Subscription1',
  }, {
    Pid: 'Sub3',
    Name: 'Subscription1',
  },
]

const schema = `
  type Serie {
    name: String!
    Subscriptions: [Subscription]
  }

  type Subscription {
    Pid: ID!
    ContentType: String!
  }

  type Query {
    Series: [Serie]
  }
  
`

const resolvers = {
  Query: {
    Series (_, params, { reply }) {
      return Series
    }
  },
  Subscription: {
    ContentType: () => 'SUB',
  },
  Serie: {
    Subscriptions (parent, params, { reply }) {
      return Subscriptions.filter( (e) => parent.subPids.includes(e.Pid))
    }
  }
}

app.register(mercurius, {
  schema,
  resolvers,
  graphiql: true
})

app.listen(3000)

I expect following response:

{
  "data": {
    "Series": [
      {
        "name": "Serie1",
        "Subscriptions": [
          {
            "Pid": "Sub1",
            "ContentType": "SUB"
          },
          {
            "Pid": "Sub2",
            "ContentType": "SUB"
          },
          {
            "Pid": "Sub3",
            "ContentType": "SUB"
          }
        ]
      },
      {
        "name": "Serie2",
        "Subscriptions": [
          {
            "Pid": "Sub1",
            "ContentType": "SUB"
          },
          {
            "Pid": "Sub2",
            "ContentType": "SUB"
          }
        ]
      },
      {
        "name": "Serie3",
        "Subscriptions": [
          {
            "Pid": "Sub1",
            "ContentType": "SUB"
          }
        ]
      }
    ]
  }
}

But i get:

{
  "data": {
    "Series": [
      {
        "name": "Serie1",
        "Subscriptions": [
          null,
          null,
          null
        ]
      },
      {
        "name": "Serie2",
        "Subscriptions": [
          null,
          null
        ]
      },
      {
        "name": "Serie3",
        "Subscriptions": [
          null
        ]
      }
    ]
  },
  "errors": [
    {
      "message": "Cannot return null for non-nullable field Subscription.ContentType.",
      "locations": [
        {
          "line": 6,
          "column": 7
        }
      ],
      "path": [
        "Series",
        "0",
        "Subscriptions",
        "0",
        "ContentType"
      ]
    },
............

If i change type and resolver name from Subscriptions to anything else all works as expected

I tried to redefine subscription rootType (https://spec.graphql.org/October2021/#sec-Root-Operation-Types) with no luck:

'use strict'

const Fastify = require('fastify')
const mercurius = require('..')

const app = Fastify()

const Series = [{
  name: 'Serie1',
  subPids: ['Sub1','Sub2', 'Sub3']
}, {
  name: 'Serie2',
  subPids: ['Sub1','Sub2']
}, {
  name: 'Serie3',
  subPids: ['Sub1']
}]

const Subscriptions = [
  {
    Pid: 'Sub1',
    Name: 'Subscription1',
  }, {
    Pid: 'Sub2',
    Name: 'Subscription1',
  }, {
    Pid: 'Sub3',
    Name: 'Subscription1',
  },
]

const schema = `
  type MySubscriptionRootType{
    any: String
  }
  schema {
    query: Query
    subscription: MySubscriptionRootType
  }
  type Serie {
    name: String!
    Subscriptions: [Subscription]
  }

  type Subscription {
    Pid: ID!
    ContentType: String!
  }

  type Query {
    Series: [Serie]
  }
  
`

const resolvers = {
  Query: {
    Series (_, params, { reply }) {
      return Series
    }
  },
  Subscription: {
    ContentType: () => 'SUB',
  },
  Serie: {
    Subscriptions (parent, params, { reply }) {
      return Subscriptions.filter( (e) => parent.subPids.includes(e.Pid))
    }
  }
}

app.register(mercurius, {
  schema,
  resolvers,
  graphiql: true
})

app.listen(3000)

Same output here

fjmoreno avatar May 04 '22 16:05 fjmoreno

Are you trying to use GraphQL Subscriptions like https://mercurius.dev/#/docs/subscriptions ?

mcollina avatar May 04 '22 17:05 mcollina

No, is not a graphql subscription, just a regular type named subscription, on provided example, Series have Subscriptions(as domain entity, not graphql subs)

fjmoreno avatar May 04 '22 17:05 fjmoreno

This is not supported, mercurius assumes Subscription is a GraphQL subscription.

mcollina avatar May 04 '22 23:05 mcollina

Why? is not a reserved word in graphql specs just a default name: https://spec.graphql.org/October2021/#sec-Root-Operation-Types.Default-Root-Operation-Type-Names

fjmoreno avatar May 05 '22 07:05 fjmoreno

No specific need, if you'd like to send a PR to support your use case it would be amazing.

mcollina avatar May 06 '22 11:05 mcollina

Ok, thanks for your time anyway

fjmoreno avatar May 06 '22 11:05 fjmoreno

I think there are two problems:

  1. No way to redefine the root operation types
  2. The Subscription type is specially treated even if the option is not set in the plugin or set as subscription: false

If that makes sense @mcollina, I'll open a couple PRs to get this sorted out.

mattcan avatar May 18 '22 05:05 mattcan

go for it!

mcollina avatar May 18 '22 08:05 mcollina

Closed by #800. If this doesn't address it fully, please reopen.

simoneb avatar Oct 05 '22 08:10 simoneb