facebook/relay

Support Generating the Client Resolver Schema from TypeScript Types

evanyeung opened this issue · 0 comments

Relay Resolvers are a relatively new feature to Relay that allows for augmenting the GraphQL schema on the client side. In contrast to client schema extensions, Relay Resolvers include an implementation for computing a new field or model. This allows for backing Relay with an external, client-side data source or computing fields based on other fields.

Currently, defining a Relay Resolver feels redundant when using a typed language. The docblock syntax used to define types and fields includes the GraphQL typenames, which often are one-to-one with the types in the TypeScript/Flow/etc. In implementation first schemas, for example Grats, the schema types are pulled directly out of the definition, reducing the amount of boilerplate and making it impossible for the schema and implementation to get out of sync.

We already have this working in Flow (see https://github.com/facebook/relay/blob/main/compiler/crates/relay-schema-generation/src/lib.rs) and would also like to support TypeScript.

Current Flow Implementation

We use the Hermes parser to generate an AST with Rust bindings. This AST is traversed in relay-schema-generation/src/lib.rs to build an IR representing the models and fields for the resolvers. We use two passes in this file: the first one collects all the models and fields and the second pass connects the fields to the models. This IR is the same as the docblock IR used to generate Resolvers from docblock comments which means it has a few quirks to work around. However, it is easier to understand than directly generating a GraphQL Schema and already has the necessary Relay codegen set up. In the future, we may directly generate GraphQL Types.

Steps to Add TypeScript Support

The simplest way we can see of adding TS support is to just map the TS nodes to the same ESTree nodes as their equivalent Flow nodes. For the simple types supported by Relay, each TS node should have a corresponding Flow node. This means the only changes necessary would be in the Hermes parser.

Future Work

While this solution should work for TypeScript, supporting more compile-to-JS languages could not be done in Hermes. Creating a well defined API directly in the GraphQL schema definition language (SDL) would be a more flexible solution. The GraphQL SDL is well defined, contains enough flexibility to add metadata necessary to run resolvers, and is serializable to easily pass the information from language specific compilers to the Relay compiler. An example of the current SDL output can be found at

favorite_page: ClientPage @relay_resolver(has_output_type: true, import_name: "favorite_page", import_path: "/path/to/test/fixture/terse-relay-resolver-with-output-type.js", fragment_name: "myRootFragment") @resolver_source_hash(value: "6debf0d3b679b66e8d0c58dbdb4d422d")