graphql-java icon indicating copy to clipboard operation
graphql-java copied to clipboard

Fields returned in introspection query are ordered alphabetically and do not preserve "declaration" order

Open marceloverdijk opened this issue 5 years ago • 4 comments

When upgrading from GraphQL-Java 11.0 to 12.0 I noticed the fields in the introspection query are suddenly ordered alphabetically. Before they were ordered in the "natural" (declaration) order they were defined in the schema, which I would prefer.

Especially with tools like GraphiQL and Prisma Playground I would like a certain / "natural" (declaration) order of my fields. E.g. first start with the id field, and not with e.g. a field alternate_email (because it starts with an a).

Probably related to #1314.

marceloverdijk avatar Apr 09 '19 20:04 marceloverdijk

Probably related to #1314.

Not probably related - definitely related

as I said then

I agree with you that a stable introspection system is a win. I have started some PRs to try and address this.

The graphql spec says nothing about a stable order when a type is asked for its fields (althought query results must be stable) and graphql-js itself just uses Object js map behavior which is also not stable.

However in terms of debuggability and predictability a stable order is important. Out SchemaPrinter already does name sorting for stability reasons. I think the graphql types themselves should give out elements in a stable manner

So I get your concerns (eg id first) but they are other competing concerns and stable ordering is the best way we think to be sensible in the face of competing concerns

Preserving "declaration syntax" is a tax on the code we are not willing to have.

We won't be changing this

bbakerman avatar Apr 10 '19 05:04 bbakerman

Thx for confirming @bbakerman

I understand the issue regarding stable order and I respect the choices made in graphql-java.

One of the great things about GraphQL is the schema and the documentation that can be provided with it. I know companies where internal business analyst are using GraphiQL instead of a dedicated business apps - and they depend on the documentation from the introspection. It's a pity that fields are mixed up then...

marceloverdijk avatar Apr 10 '19 10:04 marceloverdijk

PS: I also looked in the GraphQL spec and it does not explicitly mention the order.

However https://graphql.github.io/graphql-spec/June2018/#sec-Introspection mentions:

A GraphQL server supports introspection over its schema. This schema is queried using GraphQL itself, creating a powerful platform for tool‐building.

Take an example query for a trivial app. In this case there is a User type with three fields: id, name, and birthday.

For example, given a server with the following type definition:

type User {
  id: String
  name: String
  birthday: Date
}

The query

{
  __type(name: "User") {
    name
    fields {
      name
      type {
        name
      }
    }
  }
}

would return

{
  "__type": {
    "name": "User",
    "fields": [
      {
        "name": "id",
        "type": { "name": "String" }
      },
      {
        "name": "name",
        "type": { "name": "String" }
      },
      {
        "name": "birthday",
        "type": { "name": "Date" }
      },
    ]
  }
}

The example does preserve the declaration order.

marceloverdijk avatar Apr 10 '19 19:04 marceloverdijk

The graphql spec says nothing about a stable order when a type is asked for its fields (althought query results must be stable) and graphql-js itself just uses Object js map behavior which is also not stable.

I did some tests with graphql-js and ordering seems stable.

E.g. with:


import express from 'express';
import graphqlHTTP from '../src/';
import { buildSchema } from 'graphql';

// Construct a schema, using GraphQL schema language
var schema = buildSchema(`
  type Query {
    users: [User]
    hello: String
  }

  type User {
    id: String
    name: String
    birthday: String
  }
`);

// The root provides a resolver function for each API endpoint
var root = {
  hello: () => 'Hello world!',
};

var app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));
app.listen(4000);
console.log('Running a GraphQL API server at http://localhost:4000/graphql');

The order in the introspection query is exactly what I would expect. And if shuffle the fields in the schema, the changes are reflected in the results of the introspection query.

marceloverdijk avatar Apr 11 '19 11:04 marceloverdijk