Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow object types without fields. #368

Closed
wants to merge 1 commit into from

Conversation

dylanahsmith
Copy link
Contributor

Problem

graphql-js has an invariant that prevents the object type from having no fields, which could be useful for the result of mutation fields. Using an object type allows fields to be added to the result later, so an object type would provide forward compatibility. I would also like to remove the requirement for relay mutation payloads from having to include a clientMutationId, since I don't see a reason why it needs to be sent over the network.

The GraphQL specification has an Object type validation section, but doesn't have a restriction that prevents an object type from having no field.

The GraphQL specification does validate that a selection set on an object type must not be empty, but the __typename field can still be selected on an object type without any fields. That field wouldn't be necessary for the mutation use case, but would be useful if an object type without fields was used in a union.

Solution

Remove the invariant, since it doesn't seem necessary.

Question

There is another invariant that prevents an input object type from being empty. That is also a restriction that doesn't seem to be imposed by the GraphQL spec. Should that be removed as well?

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling 1ed83e6 on dylanahsmith:empty-object-type into * on graphql:master*.

@leebyron
Copy link
Contributor

Thanks for digging into this, unfortunately I don't think this change is what we should do.

Since GraphQL always requires you to select fields down to scalar values, an Object type without any defined fields cannot be accessed in any way in a query. This could be even more problematic for Input Objects where a required input object argument with no fields could result in a field that is impossible to query without producing an error.

In order to avoid these pitfalls, it's required that at least one field is defined. These error messages have the second-order valuable effect of catching mistakes and typos when defining a schema.

Thanks for pointing out the issue of the spec not making this clear - I can make an edit to the spec to ensure it includes that Objects, Input Objects and Interfaces must define at least one field to be valid.

@leebyron leebyron closed this Apr 25, 2016
leebyron added a commit to graphql/graphql-spec that referenced this pull request Apr 25, 2016
victorandree added a commit to victorandree/graphql-spec that referenced this pull request Aug 5, 2019
Supporting empty types, e.g. objects, input objects and interfaces without any fields, has concrete use cases.

- Support for GraphQL APIs without any `Query` operation type fields, for example, if the API only support mutations or subscriptions (see graphql#490). This allows defining an empty `Query` object type, while still supporting introspection.
- Support for algebraic data types (see graphql#568), where `__typename` is the only relevant field
- Potentially to support "well-known" (but empty) extensions of the introspection schema (see graphql#300)

This is a minimalist spec change, which simply removes the relevant items under the type validation sub sections.
It would probably be helpful to motivate the change and mention that one or more fields _should_ be present for a (typically) useful schema.

The requirement for composite types (object, input objects and interfaces) to define "one or more fields" was introduced in 0599414.
This change references graphql/graphql-js#368, motivating the change with:

> Since GraphQL always requires you to select fields down to scalar values, an Object type without any defined fields cannot be accessed in any way in a query.
> This could be even more problematic for Input Objects where a required input object argument with no fields could result in a field that is impossible to query without producing an error.

With regards to these objections:

- It's always possible to select `__typename` and therefore even empty object types can be useful (as e.g. algebraic data types)
- Passing an empty input object appears syntactically valid:

    ```gql
    mutation {
      update(input: {}) {
        name
      }
    }
    ```

I think this proposal fulfills the guiding principles by enabling new capabilities motivated by real use cases.
This change does not make any previously valid schema invalid, so largely preseves backwards compatibility.

Fixes graphql#568 and graphql#490 at the specification level.
victorandree added a commit to victorandree/graphql-spec that referenced this pull request Aug 28, 2019
Supporting empty types, e.g. objects, input objects and interfaces without any fields, has concrete use cases.

- Support for GraphQL APIs without any `Query` operation type fields, for example, if the API only support mutations or subscriptions (see graphql#490). This allows defining an empty `Query` object type, while still supporting introspection.
- Support for algebraic data types (see graphql#568), where `__typename` is the only relevant field
- Potentially to support "well-known" (but empty) extensions of the introspection schema (see graphql#300)

This is a minimalist spec change, which simply removes the relevant items under the type validation sub sections.
It would probably be helpful to motivate the change and mention that one or more fields _should_ be present for a (typically) useful schema.

The requirement for composite types (object, input objects and interfaces) to define "one or more fields" was introduced in 0599414.
This change references graphql/graphql-js#368, motivating the change with:

> Since GraphQL always requires you to select fields down to scalar values, an Object type without any defined fields cannot be accessed in any way in a query.
> This could be even more problematic for Input Objects where a required input object argument with no fields could result in a field that is impossible to query without producing an error.

With regards to these objections:

- It's always possible to select `__typename` and therefore even empty object types can be useful (as e.g. algebraic data types)
- Passing an empty input object appears syntactically valid:

    ```gql
    mutation {
      update(input: {}) {
        name
      }
    }
    ```

I think this proposal fulfills the guiding principles by enabling new capabilities motivated by real use cases.
This change does not make any previously valid schema invalid, so largely preseves backwards compatibility.

Fixes graphql#568 and graphql#490 at the specification level.
@dylanahsmith dylanahsmith deleted the empty-object-type branch December 22, 2021 01:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants