Skip to content

Add ability to implement schema using both SDL and GraphQLObjectTypes #185

@migueloller

Description

@migueloller

This is a continuation of my comments on #116.

To answer @stubailo's question:

With graphql-utilities the idea is very simple, GraphQL.js provides a JavaScript implementation to define a GraphQL schema but we could always use the less verbose schema language. The initial goal of the library was to allow anybody to build anything that could be built with GraphQL.js but using the schema language.

For example,

to build a schema:

const { __schema } = build(`
  schema {
    query: Query
  }
`, [Query]); // Query is a GraphQLType whose name is `Query`

to build a type:

const { Query } = build(`
  type Query {
    status: Boolean!
  }
`, {
  status: () => true, // here we use a shortcut for the resolver of the `status` field.
});

here's another type:

const { Weekday } = build(`
  enum Weekday {
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
    Sunday
  }
`);

A few things to note:

  • You can build more than one type in a single call to build, it would simply be exported with its name in the returned type map. When building a single type, you could return that type instead of a type map but I've found this to result in a more confusing API (the library currently does that but I was planning to remove support for it).
  • The __schema name above is a simple selection, it could be any other name but it was the one that made the most sense after much thought.
  • The template strings could be wrapped with graphql-tag for syntax highlighting and other nice perks. Implementing this would be extremely simple.
  • There are various shortcuts implemented to improve dev experience. The most useful one is the resolver shortcut, instead of having to write an object with a resolver field, you simply pass in the resolver. Here's the difference with and without:

with shortcut:

const { Query } = build(`
  type Query {
    status: Boolean!
  }
`, {
  status: () => true,
});

without shortcut:

const { Query } = build(`
  type Query {
    status: Boolean!
  }
`, {
  status: {
    resolver: () => true,
    // here you can add descriptions or deprecation reasons.
  },
});
  • I've approached this library with the mentality that you want to define as much as you can in the schema language and only use the configs for what's absolutely necessary. For example, descriptions have to provided via the schema language using comment blocks. Of course, it could be left up to the developer to do it either in the schema language or in the config file but this could cause confusion as to which description to pick if there are two present for a field (one in the config and one in the description).
  • The library currently does schema inference (like buildASTSchema) but this type of magic makes the API a bit confusing. It could be kept or removed but what I know for sure is that good error messages are essential for debugging these things.
  • Finally, the general signature of build takes the following parameters:
    • The type definition (this is a string, document, source, whatever can define the type using the schema language).
    • A config object. This is the same object that would get passed to the corresponding GraphQL.js constructor in new GraphQLSchema(config), for example. This can change if there are shortcuts.
    • An array or a thunk that resolves to an array of type dependencies. If there are any types that are referenced in the schema language definition then these types should be present here. A thunk has to be supported ti support circular references.

There are more things I have in mind for this library (like custom types for URLs, Email, etc.) but I feel like starting with build is a good start. What graphql-tools currently does with appplying resolvers by modifying the schema after the fact feels hacky, and doesn't lend itself for colocation of resolvers and definitions which is why ultimately I built graphql-utilities.

If my approach is something of interest I would love to discuss it more and potentially even make it a part of graphql-tools as I'm honestly just looking to benefit the ecosystem as a whole and not have another library to compete (https://xkcd.com/927/ heh).

Thanks for all the great work you guys have been doing with the Apollo stack. Truly amazing stuff! 😄

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementfeatureNew addition or enhancement to existing solutions

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions