Skip to content

4.0.0 alpha 1

Compare
Choose a tag to compare
@unclecheese unclecheese released this 17 Feb 04:20

This is the first alpha release of GraphQL 4

Changelog

For more a high-level view of what has changed in GraphQL 4, see the upgrade guide.

Changes since 3 Feb 2021

  • Refactor context provider API so that they now plug into QueryHandlerInterface. They
    can set and get their own context based on their own internal logic. Before:
    $user = $context['currentUser']; after: $user = UserContextProvider::get($context)

  • BuildState API is gone. Use new SchemaContextProvider in resolvers. Pass SchemaContext
    objects to the small number of classes that needed it in their internals.

  • AbstractNestedInputPlugin is gone. This never made any sense to tie something
    so utilitarian to an arbitrary inheritance chain. It has been refactored as NestedInputBuilder
    and is far more single-purpose. No longer concerned with model and field mapping, but rather
    just building recursive input types and adding them to the schema.

  • Refactor QuerySort, QueryFilter to use input builder

  • Field mapping is no longer exhaustively encoded in the resolvers. New
    SchemaContextProvider allows resolvers to look at the schema as persisted to a
    PHP array in the code gen and invoke methods like $schema->mapField($type, $fieldName)

  • No more resolveContext for DataObject\Resolver since field mapping is handled externally now

  • Migrate type Controller::introspectTypes to standalone service (SchemaTranscriber)
    invoked through event dispatcher

  • Remove IntrospectionProvider extension. Static only. Leaving it to the user to decide never made any sense, and it just slowed down the UI in the CMS. Now that we're doing code gen, it seems like the static solution is more consistent.

  • Remove ModelConfigurationProvider: Didn't make any sense. Models are now
    responsible for fetching their own configurations.

  • Remove defaultResolver: Didn't make any sense. Just set a default resolver
    property and allow it to be overridden.

  • Resolver discovery is now lazy to avoid race conditions in config. If resolvers
    are null at code gen time, discovery is invoked and applied.

  • Controller now only accepts a schema key and uses SchemaFactory to boot.

  • Schema::quiet() is gone. Schema is quiet by default to better support autobuilding
    and test suites. Opt into verbose with setVerbose(true).

  • CSRFMiddleware and HTTPMethodMiddleware now rely on new ContextProviders
    to better encapsulate their state concerns.

  • Better error reporting:

    • QueryHandler now pretty prints the stack trace
    • Resolver level errors now throw ResolverFailure which express tons of useful
      context, including the query path, the field, the type, the args, and most importantly,
      the resolver chain. No more guessing which closure failed.
    • ResolverFailure relies on new resolverComposition field in encoded types.
    • Updates to code gen templates to support the above, and other tidiness like
      variable assignment to save code execution and comments to show closing bracket relationships.
  • ComposedResolver is now stateful, mostly for diagnostic purposes. Before:
    ComposedResolver::create(): Closure after: ComposedResolver::create($list)->toClosure()

  • All resolvers use ComposedResolver for consistency, even when no middle/afterwares

  • ComposedResolver no longer needs separate arguments for primary, before, and after
    resolvers. Just a stack that leaves ordering a concern of the code composing the class.
    (this was a @todo annotation FWIW)

  • SchemaModelInterface now must declare getPropertyForField (gql field -> object property mapping)

  • SchemaModelInterface now must declare getSchemaContext and getModelConfiguration

  • New hasNativeField in FieldAccessor helps with knowing what fields are
    filterable/sortable. Basically ORM insight.

  • Fields using the model property (a bit of a polymorphic hack to support
    cases like CMS needing to know what the SiteTree model is named), will
    get just-in-time assignment before code generation time to prevent race conditions
    in the config.

  • New suite of relational FakeProduct objects for testing nested queries, filters, mutations.

  • New top-to-bottom integration test that creates, updates, and reads nested data structures with filters/sorting, field aliases, etc.

  • NB: CodeGenerationStore is now responsible for type mapping and field mapping. This
    is a leaky abstraction as it's tightly coupled to SchemaContext now.

  • New StorableSchema layer eliminates unpredictable state of Schema through process(). The readonly value object returned by createStorableSchema() is expected to
    be a complete set of primitive objects that are consumable by a storage service.

  • SchemaFactory is now SchemaBuilder, which has four clearly defined functions, and eliminates the confusion around using Schema at query time:

    • getConfig(string $schemaKey): ?SchemaContext -- Get the cached configuration of a Schema. Useful for resolvers
    • boot(string $schemaKey): Schema -- Load all the configuration in to a Schema object. Useful for the configuration/build process.
    • getSchema(string $schemaKey): ?GraphQLSchema -- Retrieve a queryable graphql-php Schema object from the storage service. Useful at query time.
    • build(Schema $schema, bool $clear = false): GraphQLSchema -- put the Schema through a storage service and return its queryable schema
  • SchemaStorageInterface is now the concern of SchemaBuilder rather than Schema, which results in a diminished API surface for Schema.

  • Validation of Schema moved to StorableSchema, as this is the only time the schema truly needs to be valid (before storage)

  • Type/field mapping done just-in-time for schema storage

  • Prefer event dispatcher over extend() hooks in controller

  • SchemaContext is now SchemaConfig

  • Schema has new getState() for persisting state during build

  • Improved handling of "empty" schemas that shouldn't be built, but also shouldn't error (e.g. default out of the box)