Skip to main content
Version: v5 (rc)

wrapPlans resolver emulation warning

You're probably here because you just saw a warning like:

[WARNING]: `wrapPlans(...)` plugin WrapPlansPlugin_1 has wrapped the default
plan resolver at field coordinate User.email. If this is an impure schema (one
that mixes traditional resolvers with Gra*fast* plan resolvers) then this may
result in hard to track down issues - hence this warning. See
https://err.red/pwpr for full explanation and proposed solutions.

Plan resolvers vs traditional resolvers

Grafast, the GraphQL engine powering PostGraphile, runs on the basis of plan resolvers. Everything built in to PostGraphile uses these plan resolvers - by default, PostGraphile produced a "pure" Grafast schema.

However, Grafast also supports emulating traditional resolvers (see Using with existing schema in the Grafast docs) for compatibility with traditional GraphQL.js-style schemas, and it's possible to add these traditional resolvers to a PostGraphile schema via extendSchema() or other methods. Adding traditional resolvers to a Grafast schema makes the schema "impure" - it should still work fine, but it's less performant and there are caveats to be aware of, such as this one.

Pure Grafast schemas

If you have a pure Grafast schema - a schema that only uses plan resolvers (no resolve or subscribe traditional resolvers) - then you can safely ignore this warning, and can even prevent it being emitted using disableResolverEmulationWarnings: true.

Impure Grafast schemas

When a traditional resolver is seen, Grafast enters "resolver emulation" mode. In this mode, among other changes it no longer uses the default plan resolver when a field has no plan.

However, wrapPlans() will always ensure the field has a plan, and if there is no plan to wrap then it will default to wrapping the defaultPlanResolver.

Adding a plan to a field that was called in resolver emulation mode will change the data to be fed into the resolver, thereby causing breakage.

Since plan wrapping occurs at schema build time, not at runtime, PostGraphile cannot know whether or not resolver emulation will be enabled. Since the issues this cause can be hard to track down otherwise, out of an abundance of caution we raise this warning for users who are applying very broad plan wrapping logic to help them know which specific fields might surface an issue.

Resolution

To resolve this:

  1. Add a (non-default) plan resolver for the field you are wrapping, or
  2. Avoid wrapping the default plan resolver, or
  3. Set disableResolverEmulationWarnings: true when calling wrapPlans() once you have confirmed it is safe for your schema.

Avoid wrapping default plan resolvers

To avoid wrapping the default plan resolver, consider logic like this:

const MyPlugin = wrapPlans(
(context, build, field) => {
const {
grafast: { defaultPlanResolver },
} = build;
const plan = field.extensions?.grafast?.plan ?? defaultPlanResolver;
// Don't wrap the default plan resolver
if (plan === defaultPlanResolver) return null;

// ...
},
// ...
);

Disable the warning

If you're sure this part of the schema won't be impacted by resolver emulation, you can disable the warning:

const MyPlanWrapperPlugin = wrapPlans(rules, {
name: "MyPlanWrapperPlugin",
disableResolverEmulationWarnings: true,
});
// Or:
const MyOtherPlanWrapperPlugin = wrapPlans(filterFn, ruleFn, {
name: "MyOtherPlanWrapperPlugin",
disableResolverEmulationWarnings: true,
});