Graphql-tools: transformSchema: remove input fields by name.

Created on 3 Feb 2019  路  10Comments  路  Source: ardatan/graphql-tools

In my current schema, I have some about 15-ish types like this:

type CoffeShop {
    name: String!
    createdBy: User!
   ...
}

all of them having a createdBy-reference to the user. The complete schema is then generated, with queries, mutations and all. However, we don't want users to be able to specify createdBy when they are doing mutaitons, as we get that information from authentication-information.

We have tried to remove overy instance of createdBy from the generated input-types, but this is fast turning into a chore.

After looking at transformSchema, we see that it could possibly be used for this. However, I find it a bit difficult to know exactly how I should transform. I could not find this information in the documentation. What fields in the schema would be input?

Basically, I'd like to remove every field of type input that has the name createdBy.

docs

Most helpful comment

Try out the new FilterInputObjectFields transform from #1551:

npx match-version @graphql-tools 6.0.8-alpha-4aeb995.0

Usage as follows:

  describe('transform input object fields', () => {
    test('filtering works', async () => {
      const schema = makeExecutableSchema({
        typeDefs: `
          input InputObject {
            field1: String
            field2: String
          }

          type OutputObject {
            field1: String
            field2: String
          }

          type Query {
            test(argument: InputObject): OutputObject
          }
        `,
        resolvers: {
          Query: {
            test: (_root, args) => {
              return args.argument;
            }
          }
        }
      });

      const transformedSchema = wrapSchema(schema, [
        new FilterInputObjectFields(
          (typeName, fieldName) => (typeName !== 'InputObject' || fieldName !== 'field2'),

          // Below is where you can supply the targetSchema with a value for the
          // stripped input field -- if you want

          // delegationContext gives you access to the overall delegationContext
          // i.e. the relevant options from delegateToSchema
          // with the graphql context under delegationContext.context, for example

          // request gives you access to the request so far, including variables, etc.

          (typeName, inputObjectNode, /* delegationContext, request */) => {

            if (typeName === 'InputObject') {
              return {
                ...inputObjectNode,
                fields: [...inputObjectNode.fields, {
                  kind: Kind.OBJECT_FIELD,
                  name: {
                    kind: Kind.NAME,
                    value: 'field2',
                  },
                  value: astFromValue('field2', GraphQLString),
                }],
              };
            }
          }
        )
      ]);

      const query = `{
        test(argument: {
          field1: "field1"
        }) {
          field1
          field2
        }
      }`;

      const result = await graphql(transformedSchema, query);
      expect(result.data.test.field1).toBe('field1');
      expect(result.data.test.field2).toBe('field2');
    });
  });

All 10 comments

+1, Tried FilterByTypes and FilterRootFields couldn't make it work.

As a temporary workaround, I created a rough schema-generator for this. It is very basic, but we have used it successfully for about a month now, doing most of what we need in a very dynamic way. It is of course not an ideal solution. https://github.com/runar-indico/graphql-schema-transformer

Moving to v5.1, reopening to move any relevant discussion here.

This is not as simple as changing the input objects, because you also have to provide a mechanism for setting default values for non optional input values

@yaacovCR Should I open a separate issue to deal with query and mutation arguments?

I think it would all be part of same transformer, so can be tracked together

See #1551 which allows filtering and renaming input fields but does not yet address fully the issue of modifying the arguments.

Please comment there on desired approach.

1551 has been improved to allow setting default values for filtered input fields at schema generation time or at delegation time..

Try out the new FilterInputObjectFields transform from #1551:

npx match-version @graphql-tools 6.0.8-alpha-4aeb995.0

Usage as follows:

  describe('transform input object fields', () => {
    test('filtering works', async () => {
      const schema = makeExecutableSchema({
        typeDefs: `
          input InputObject {
            field1: String
            field2: String
          }

          type OutputObject {
            field1: String
            field2: String
          }

          type Query {
            test(argument: InputObject): OutputObject
          }
        `,
        resolvers: {
          Query: {
            test: (_root, args) => {
              return args.argument;
            }
          }
        }
      });

      const transformedSchema = wrapSchema(schema, [
        new FilterInputObjectFields(
          (typeName, fieldName) => (typeName !== 'InputObject' || fieldName !== 'field2'),

          // Below is where you can supply the targetSchema with a value for the
          // stripped input field -- if you want

          // delegationContext gives you access to the overall delegationContext
          // i.e. the relevant options from delegateToSchema
          // with the graphql context under delegationContext.context, for example

          // request gives you access to the request so far, including variables, etc.

          (typeName, inputObjectNode, /* delegationContext, request */) => {

            if (typeName === 'InputObject') {
              return {
                ...inputObjectNode,
                fields: [...inputObjectNode.fields, {
                  kind: Kind.OBJECT_FIELD,
                  name: {
                    kind: Kind.NAME,
                    value: 'field2',
                  },
                  value: astFromValue('field2', GraphQLString),
                }],
              };
            }
          }
        )
      ]);

      const query = `{
        test(argument: {
          field1: "field1"
        }) {
          field1
          field2
        }
      }`;

      const result = await graphql(transformedSchema, query);
      expect(result.data.test.field1).toBe('field1');
      expect(result.data.test.field2).toBe('field2');
    });
  });

Should be available in latest release, needs docs

Was this page helpful?
0 / 5 - 0 ratings