question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[RFC] GraphQL Provider Framework

See original GitHub issue

Background

One of the core responsibilities of Keystone is to generate a GraphQL API. In the common use case, this API consists of CRUD operations over a collection of lists. It also provides authentication mutations, custom types/queries/mutations, as well as an application version query.

The current implementation of each of these features is tightly woven into the core of Keystone. This tight coupling is a problem, as it blurs the lines between each of the concerns, as well as making it hard to introduce new features into the GraphQL API.

Proposal

I would like to propose the introduction of a GraphQL Provider Framework. While this sounds big and impressive, it can be easily summarised by the following class API definition:

class Provider {
  constructor() {}

  getTypes({ schemaName }) {
    return [];
  }
  getQueries({ schemaName }) {
    return [];
  }
  getMutations({ schemaName }) {
    return [];
  }

  getTypeResolvers({ schemaName }) {
    return {};
  }
  getQueryResolvers({ schemaName }) {
    return {};
  }
  getMutationResolvers({ schemaName }) {
    return {};
  }
}

Each feature of Keystone which generates graphQL API surface area would be encapsulated in a Provider class, which has methods for generating the type definitions and resolvers required by Apollo.

Keystone would keep track of an array of providers, and iterate over these to generate the combined set of type definitions and resolvers which make up the complete graphQL API.

Discussion

How would this impact the current implementation?

The code which currently lives in Keystone.getAdminSchema() and Keystone.getTypeDefs() would be greatly simplified to iteration over the list of providers. All the functionality would be shifted into four separate providers:

  • ListCRUDProvider
  • ListAuthProvider
  • AppVersionProvider
  • CustomProvider

How would I add my own Provider to Keystone?

A system writer would be able to implement their own Provider class and then call Keystone.addProvider({ provider }).

Why don’t we just have getTypedefs and getResolvers as the Provider API?

The way Keystone currently combines the different pieces of the graphQL API means that the types, queries and mutations all need to be handled individually. We could definitely write some kind of BaseProvider class which had getTypedefs() and getResolvers() and leveraged the other methods to generate valid results which could be passed directly into ApolloServer. I’m 50/50 on whether we want to make this the default or not.

What benefits to we expect to get out of this?

  • The existing code will be better organised. For example, the AppVersionProvider functionality will be able to live in one place in a single module, rather than being spread throughout Keystone/index.js.
  • Separation of concerns will be more obvious. For example, the auth aspects of Keystone are actually quite different to the CRUD aspects, however in order to generate our graphQL API these are currently somewhat conflated.
  • It will help us think about our Keystone APIs as a composition of individual providers, rather than a big mish-mash of misc things.
  • It will provide an alternate way for developers to integrate new pieces of API into the system beyond the existing custom type/query/mutation API.
  • It moves us closer to the goal of being able to support CRUD APIs across multiple data sources.
  • It gives us a new way of thinking about the Admin UI and what it does and does not support.
  • …probably a lot of other things I haven’t considered 🤷‍♂

What could possibly go wrong?

I’ve prototyped out an implementation of this API (#2420) and have verified that this API is sufficient to match the existing functionality. Also, the refactor does not appear to introduce any complexity beyond what already exists. I’m rather confident that this is a good design, but I’m open to questions or concerns that I may have overlooked.

How will all this get implemented.

I will implement a series of PRs, each of which introduces a single piece of the functionality required to fully convert to this API. This will hopefully make it easier to review each individual PR and also provide us with some checkpoints to identify any bugs are design issues which arise during the conversion process.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:6 (6 by maintainers)

github_iconTop GitHub Comments

3reactions
gautamsicommented, Feb 27, 2020

Would this make sense to have GraphQL Subscription as part of custom provider. I know the lists don’t support subscription yet but I can have custom code for subscription which I dont want to mount another graphql middleware

class Provider {
  constructor() {}
// -----
  getSubscriptions({ schemaName }) {
    return [];
  }
  getSubscriptionResolvers({ schemaName }) {
    return {};
  }
}
0reactions
timlesliecommented, Mar 2, 2020

Yep, this change will definitely unlock the ability to add support for Subscriptions to Keystone 👍

Read more comments on GitHub >

github_iconTop Results From Across the Web

Apollo-graphql-at-enterprise-scale-final.pdf
This chapter will introduce you to the notion of creating a unified, federated data graph in an effort to leverage the benefits of...
Read more >
Query record data using the GraphQL API framework
Create a custom GraphQL API to query record data from a component or a third-party system.
Read more >
Serving over HTTP - GraphQL
Here are some guidelines for setting up a GraphQL server to operate over HTTP. Web Request Pipeline#. Most modern web frameworks use a...
Read more >
GraphQL API style guide - GitLab Docs
GraphQL API style guide. This document outlines the style guide for the GitLab GraphQL API. How GitLab implements GraphQL. We use the GraphQL...
Read more >
GraphQL - Wikipedia
GraphQL is an open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data. GraphQL was developed ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found