Mike Boutin
Mike Boutin

Reputation: 5347

GraphQL - passing an object of non specific objects as an argument

I am very new to GraphQL. I'm trying to pass an object like this one as an argument:

{
  filters: {
    status: 'approved',
    id: {
      LESS_THAN: 200 
    }
  }
}

Or this object can be like this either;

{
  filters: {
    status: ['approved', 'pending'],
    id: 200
  }
}

I know all properties that can be in this object, but all of these properties can be a string/int or an object.

I tried to define it like this but it obviously didn't work:

args: {
    filters: { type: new GraphQLNonNull(new GraphQLNonNull(GraphQLString)) },
},

I'm trying to define the argument with a GraphQL type GraphQLInputObjectType.

const OffersFiltersType = new GraphQLInputObjectType({
  name: 'Filters',
  description: '...',
  fields: () => ({})
    id: {
      type: new GraphQLNonNull({
        name: 'Id',
        description: '...',
        fields: {

        }
      }),
      resolve: (offer) => offer.id
    },
  }),
});

But how can i specify to this type that my id can be either a int or an object?

This is my Query definition:

const QueryType = new GraphQLObjectType({
  name: 'Query',
  description: '...',
  fields: () => ({
    offers: {
      type: OffersType,
      args: {
        limit: { type: GraphQLInt },
        page: { type: GraphQLInt },
        sort: { type: GraphQLString },
        filters: { [HERE] }
      },
      resolve: (root, args, context, info) => {
        const gqlFields = graphqlFields(info);
        const fields = Object.keys(gqlFields.offer);
        const queryArgs = args;

        queryArgs.fields = fields;

        return getOffers(queryArgs);
      }
    },
  }),
});

And this is my request with superagent

const getOffers = (args) => {
  const queryArgs = args;

  if (typeof queryArgs.limit !== 'undefined') {
    queryArgs.limit = args.limit;
  } else {
    queryArgs.limit = Number.MAX_SAFE_INTEGER;
  }

  return new Promise((fulfill, reject) => {
    request
      .get(API_URL)
      .query(qs.stringify(args))
      .end((err, res) => {
        if (err) {
          reject(err);
        }

        fulfill(res);
      });
  });
};

I need this object to construct a query in my resolve function. Thank you all for your help! I only need simple advices!

Upvotes: 2

Views: 3156

Answers (1)

ssube
ssube

Reputation: 48247

This is not allowed, by design: https://github.com/graphql/graphql-js/issues/303

GraphQL does not support unknown property names, largely because it would make the schema meaningless. The example given is a simple typo:

If you have the query query ($foo: String) { field(arg: $foo) } and the variables { "fooo": "abc" }, we currently flag this as an error, but we could potentially miss this typo if we did not raise errors.

The schema is meant to ensure compatibility between servers and clients, even across versions, and allowing unknown properties would break that.

There is a merge request open for this in the GraphQL-JS repo, but it is still being debated and has the same problems with typos and general inconsistency.

The idea of returning a primitive or object runs into a similar problem. When accepting an object, you need to list the properties you're expecting and the query will validate those against the schema. The properties, and their types and null-ness, must be known ahead of time for you (and the parser) to build the query and definitely need to be known when you validate.

If you could accept a primitive or object, you would have to specify the fields on that object, but those could not possibly exist on the primitive. That's a problem.

Upvotes: 1

Related Questions