Skip to content

[RFC] Allows use of generated schemas for execution.#469

Merged
leebyron merged 1 commit into
masterfrom
execute-with-client-schema
Aug 25, 2016
Merged

[RFC] Allows use of generated schemas for execution.#469
leebyron merged 1 commit into
masterfrom
execute-with-client-schema

Conversation

@leebyron

@leebyron leebyron commented Aug 24, 2016

Copy link
Copy Markdown
Contributor

Right now our generated schemas (built from introspection, built from AST) explicitly do not allow their use in execution. They throw as soon as any resolver function is called. This conservative behavior was appropriate for early versions where we wanted to limit the surface area under use. Today it's becoming more clear that there are immediately valuable use cases for using generated schema in execution.

The ability to execute will still be somewhat limited: generated schema do not contain enough information to resolve Interface and Union types, and coerce values for custom Scalars.

Case 1: Resolvers live in your domain models, AST schema is useful:

const schema = buildASTSchema(parse(`type MyTypeSystem { ... }`));
class MyObject { ... }
class MyQueryRoot { ... }
const response = graphql(schema, query, new MyQueryRoot())

This is pretty compelling for simpler schema. You can define your schema entirely in AST and allow resolvers to completely exist outside the GraphQL type domain. This approach is now immediately useful thanks to @lacker's #468.

Case 2: Querying your local cache:

const schema = buildClientSchema(introspection);
const response = graphql(schema, query, myGraphQLCache);

I admit that this use case is more experimental and less thought through, but I believe that contributors & community may take this idea further. Conceptually it's compelling: given a query I want to submit and my local cache of results, what partial results can I use right away before the server returns? I'm absolutely sure there are missing pieces to truly enable this, but this should be a first step.

@leebyron

leebyron commented Aug 24, 2016

Copy link
Copy Markdown
Contributor Author

Right now our generated schemas (built from introspection, built from AST) explicitly do not allow their use in execution. They throw as soon as any resolver function is called. This conservative behavior was appropriate for early versions where we wanted to limit the surface area under use. Today it's becoming more clear that there are immediately valuable use cases for using generated schema in execution.
@leebyron leebyron force-pushed the execute-with-client-schema branch from 234f2ff to 930d489 Compare August 24, 2016 22:05
@ghost ghost added the CLA Signed label Aug 24, 2016
@lacker

lacker commented Aug 24, 2016

Copy link
Copy Markdown

Case 1 is really nice here - it lets people set up a graphql server without learning the API for the GraphQLSchema, GraphQLObjectType and so on. So +1 for making this change.

Just a style thing but what do you think about a helper function that does buildASTSchema(parse(x)) ? buildSchema ? If this is going to be in the hello world of express-graphql (which I think it should be) it's one notch nicer to have people import one function rather than two.

@leebyron

Copy link
Copy Markdown
Contributor Author

I like that idea!

@josephsavona

Copy link
Copy Markdown
Contributor

This is great. Case 1 seems like a really solid use-case to make prototyping and iteration on servers easier.

ship it!

@stubailo

stubailo commented Aug 24, 2016

Copy link
Copy Markdown

Love case 1, should be useful.

As for case 2:

I'm absolutely sure there are missing pieces to truly enable this, but this should be a first step.

There are two disadvantages using this in Apollo Client or a similar tool, for me:

  1. This requires the schema, whereas it's actually possible to execute a graphql query against static data without a schema, as we have demonstrated in the AC implementation.
  2. This package (graphql-js) is not optimized for having a small footprint, because most of the modules have a lot of internal dependencies, in addition, a lot of the utilities assume schema knowledge because in some cases it's necessary to disambiguate certain edge cases. This means we have our own implementations of, for example, argument parsing: https://github.com/apollostack/apollo-client/blob/919340626a40eb1a96b9b4a1e035694d8cac2302/src/data/storeUtils.ts#L45

I'd be happy to collaborate with anyone to unblock this use case - there might be some small changes that can be made to make it possible for anyone to build a nice client-side cache using this package, which I think would be a big win for the community overall, and reduce the amount of custom work we need to do in Apollo Client.

@josephsavona josephsavona reopened this Aug 24, 2016
@josephsavona

Copy link
Copy Markdown
Contributor

Fat fingers on mobile phone, my bad

@leebyron

Copy link
Copy Markdown
Contributor Author

@stubailo - yeah, I'm with you there. I think the first case is compelling and the second is only just interesting.

There's definitely some fruit for future exploration in what you're talking about, but of course if you're executing queries locally without a schema, then this is kind of moot since it's about the behavior of the schema itself :)

@leebyron leebyron merged commit e834097 into master Aug 25, 2016
@leebyron leebyron deleted the execute-with-client-schema branch August 25, 2016 02:30
@stubailo

Copy link
Copy Markdown

Sigh......... I got nerd sniped. Feast your eyes: https://github.com/stubailo/graphql-anywhere

Next up, refactoring Apollo Client to use this package to read from the cache!

@Gregoor

Gregoor commented Oct 2, 2016

Copy link
Copy Markdown

Heya, I'm trying to use the generated schema with Relay, but I'm getting the "Generated Schema cannot use Interface or Union types for execution." error. From what I can tell, for nodeDefinitions to work, we need interfaces.
If someone can highlight what's holding Interface support back, I'd get started on working it in.

@stubailo

stubailo commented Oct 2, 2016

Copy link
Copy Markdown

Hey, give this package a try: https://github.com/apollostack/graphql-tools

It's like buildSchema but with support for resolvers, interfaces, etc.

yaacovCR added a commit to yaacovCR/graphql-js that referenced this pull request Jun 9, 2026
Add `supplementalConfig` to `buildSchema`, `buildASTSchema`, and `extendSchema` so SDL-defined schema elements can receive constructor-only configuration that SDL cannot express. The option is validated by default and can be bypassed with `assumeValidSupplementalConfig` for config that has already been checked.

The schema-level config is keyed by schema element kind and GraphQL name:

- `scalarTypes`: `serialize`, `parseValue`, `parseLiteral`, `coerceOutputValue`, `coerceInputValue`, `coerceInputLiteral`, `valueToLiteral`, and `extensions`.

- `objectTypes`: `fields`, `isTypeOf`, and `extensions`.

- `interfaceTypes`: `fields`, `resolveType`, and `extensions`.

- `unionTypes`: `resolveType` and `extensions`.

- `enumTypes`: `values` and `extensions`; enum values can define an internal `value` and `extensions`.

- `inputObjectTypes`: `fields` and `extensions`.

- `directives`: `args` and `extensions`.

- `extensions`: schema extensions.

Field supplements can be a resolver function or an object with `resolve`, `subscribe`, `args`, and `extensions`. Argument, input field, directive argument, enum value, and type supplements apply only to schema elements declared or extended by the SDL document, and unmatched supplemental config is rejected by default.

This lets SDL own the type-system shape while JavaScript supplies runtime behavior and host-language metadata: field resolvers, subscription functions, abstract type resolution, object type predicates, custom scalar coercion and literal conversion, enum runtime values, and extensions.

Related issues: graphql#497, graphql#499, graphql#516, graphql#525, graphql#604, graphql#622, graphql#1379, graphql#1858.

Related prior PRs: graphql#469, graphql#947, graphql#1384, graphql#1987.
yaacovCR added a commit to yaacovCR/graphql-js that referenced this pull request Jun 10, 2026
Add `supplementalConfig` to `buildSchema`, `buildASTSchema`, and `extendSchema` so SDL-defined schema elements can receive constructor-only configuration that SDL cannot express. The option is validated by default and can be bypassed with `assumeValidSupplementalConfig` for config that has already been checked.

The schema-level config is keyed by schema element kind and GraphQL name:

- `scalarTypes`: `serialize`, `parseValue`, `parseLiteral`, `coerceOutputValue`, `coerceInputValue`, `coerceInputLiteral`, `valueToLiteral`, and `extensions`.

- `objectTypes`: `fields`, `isTypeOf`, and `extensions`.

- `interfaceTypes`: `fields`, `resolveType`, and `extensions`.

- `unionTypes`: `resolveType` and `extensions`.

- `enumTypes`: `values` and `extensions`; enum values can define an internal `value` and `extensions`.

- `inputObjectTypes`: `fields` and `extensions`.

- `directives`: `args` and `extensions`.

- `extensions`: schema extensions.

Field supplements can be a resolver function or an object with `resolve`, `subscribe`, `args`, and `extensions`. Argument, input field, directive argument, enum value, and type supplements apply only to schema elements declared or extended by the SDL document, and unmatched supplemental config is rejected by default.

This lets SDL own the type-system shape while JavaScript supplies runtime behavior and host-language metadata: field resolvers, subscription functions, abstract type resolution, object type predicates, custom scalar coercion and literal conversion, enum runtime values, and extensions.

Related issues: graphql#497, graphql#499, graphql#516, graphql#525, graphql#604, graphql#622, graphql#1379, graphql#1858.

Related prior PRs: graphql#469, graphql#947, graphql#1384, graphql#1987.
yaacovCR added a commit to yaacovCR/graphql-js that referenced this pull request Jun 21, 2026
Add `supplementalConfig` to `buildSchema`, `buildASTSchema`, and `extendSchema` so SDL-defined schema elements can receive constructor-only configuration that SDL cannot express. The option is validated by default and can be bypassed with `assumeValidSupplementalConfig` for config that has already been checked.

The schema-level config is keyed by schema element kind and GraphQL name:

- `scalarTypes`: `serialize`, `parseValue`, `parseLiteral`, `coerceOutputValue`, `coerceInputValue`, `coerceInputLiteral`, `valueToLiteral`, and `extensions`.

- `objectTypes`: `fields`, `isTypeOf`, and `extensions`.

- `interfaceTypes`: `fields`, `resolveType`, and `extensions`.

- `unionTypes`: `resolveType` and `extensions`.

- `enumTypes`: `values` and `extensions`; enum values can define an internal `value` and `extensions`.

- `inputObjectTypes`: `fields` and `extensions`.

- `directives`: `args` and `extensions`.

- `extensions`: schema extensions.

Field supplements can be a resolver function or an object with `resolve`, `subscribe`, `args`, and `extensions`. Argument, input field, directive argument, enum value, and type supplements apply only to schema elements declared or extended by the SDL document, and unmatched supplemental config is rejected by default.

This lets SDL own the type-system shape while JavaScript supplies runtime behavior and host-language metadata: field resolvers, subscription functions, abstract type resolution, object type predicates, custom scalar coercion and literal conversion, enum runtime values, and extensions.

Related issues: graphql#497, graphql#499, graphql#516, graphql#525, graphql#604, graphql#622, graphql#1379, graphql#1858.

Related prior PRs: graphql#469, graphql#947, graphql#1384, graphql#1987.
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.

5 participants