Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for defining field extensions property in Apollo resolvers #1279

Closed
mattdean-digicatapult opened this issue Jan 24, 2020 · 4 comments

Comments

@mattdean-digicatapult
Copy link

What I'm trying to do:

My end goal is to implement DoS protection using graphql-query-complexity and more specifically using the fieldExtensionsEstimator from that library. This makes use of the field extensions property in graphql-js to label individual fields with a complexity cost function allowing for a very expressive cost calculation mechanism.

The problem

As far as I can tell there is no supported/documented mechanism for defining field extensions in graphql-tools so I would have to define my schema using graphql-js directly. Having said that the following does work:

const resolvers = {
  Query: {
    tests: {
      resolve: (_, args) => {
        const result = []
        for (let index = args.startIndex; index < args.endIndex; index++) {
          result.push({ index })
        }
        return result
      },
      extensions: {
        // complexity field extension used by fieldExtensionsEstimator
        complexity: ({ args, childComplexity }) => childComplexity * (args.endIndex - args.startIndex),
      },
    },
  }
}

A more complete working example can be found at digicatapult/graphql-complexity-experiment.

The problem therefore is that the extensions property in the above is both not documented and not included in the typings.

Solution

Firstly modify the interface IResolverOptions to include the extensions property like:

export interface IResolverOptions<TSource = any, TContext = any, TArgs = any> {
  fragment?: string;
  resolve?: IFieldResolver<TSource, TContext, TArgs>;
  subscribe?: IFieldResolver<TSource, TContext, TArgs>;
  extensions?: Readonly<Record<string, any>>;
  __resolveType?: GraphQLTypeResolver<TSource, TContext>;
  __isTypeOf?: GraphQLIsTypeOfFn<TSource, TContext>;
}

to match the equivalent property in graphql-js. Secondly this behaviour should be documented in the apollo-server docs.

Can I do this?

If the above sounds good then I would be happy to submit a PR for this.

@yaacovCR
Copy link
Collaborator

I hope Apollo accepts this suggestion. there has not been much activity on this repository for some number of months now. (See #1206) I would be more than happy to accept a pull request on the fork and then I would bundle in #1206.

@VictorGaiva
Copy link

This Extensions field could be just the solution for the issue with not being able to send a dynamic token for authentication for Subscriptions.

I was able to do so with this field but the lack of typing and documentation makes me fear it would eventually be removed

@yaacovCR
Copy link
Collaborator

yaacovCR commented Apr 1, 2020

Fold into #1306

@harshil4076
Copy link

Unable to add extra Metadata to field.extensions - HELP
I followed the steps in https://blog.grandstack.io/authorization-in-graphql-using-custom-schema-directives-eafa6f5b4658 to add a custom directive called @extensionsDir to add extensions on fields.
This is what my server file looks like.
class ExtensionDirective extends SchemaDirectiveVisitor {
visitFieldDefinition(field) {
field.extensions = "Demo"
console.log(field)
}
}
const schema = makeAugmentedSchema({
typeDefs,
schemaDirectives: {
extensionsDir: ExtensionDirective,
},
})
directive declaration is directive @extensionsDir on FIELD_DEFINITION
usgae :
type Sample {
sampleField: Boolean! @extensionsDir
}
The console log shows that its successfully added to .extensions but when I fetch introspection results in the client, the client schema does not indicate changes made to the field on that type. However the directives list does show an object named extensionsDir.
Am I missing something here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants