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

Accept an object as the argument to graphql() #356

Closed
taion opened this issue Apr 12, 2016 · 12 comments
Closed

Accept an object as the argument to graphql() #356

taion opened this issue Apr 12, 2016 · 12 comments

Comments

@taion
Copy link
Contributor

taion commented Apr 12, 2016

This came up in the context of graphql/graphql-relay-js#74 (comment), but I think that given the number of arguments to graphql(): https://github.com/graphql/graphql-js/blob/v0.5.0/src/graphql.js#L43-L50, it would make more sense for it to take an object rather than a list of arguments.

Among other things, this would make it easier to provide backward compatibility with the v0.4.x API, and also just make it less error-prone for those of us not using e.g. Flow to get all the arguments right.

@helfer
Copy link
Contributor

helfer commented Apr 13, 2016

Couldn't agree more. Should be relatively easy work for a PR

@taion
Copy link
Contributor Author

taion commented Apr 13, 2016

Yup! Question is – would it be acceptable to do this with a backward compat hook such that the old 0.4.x API (without context) still works? I feel like that would make it significantly easier (along with other backward compat affordances) for users to move forward. I haven't upgraded yet, given that graphql-relay hasn't released yet, but I'm not looking forward to the upgrade.

@helfer
Copy link
Contributor

helfer commented Apr 13, 2016

I personally don't think it's worth complicating the code going forward to keep back-compatibility with 0.4.0. I'd prefer having a clean solution for future upgrades, but maybe that's just because I don't yet have anything in production using graphql.

@helfer
Copy link
Contributor

helfer commented Apr 13, 2016

Another thing this proposal would let us do is pass an option to graphql which tells it to format errors with the default function. I find it quite inconvenient to have to format them myself now.

@helfer
Copy link
Contributor

helfer commented Apr 15, 2016

To add to what was said above: at this point making the interface backwards-compatible would require making it backwards-compatible with both v0.5.* and v0.4.*, which frankly I don't think is even possible because the arguments are optional. If someone passes three arguments, there's no way of knowing whether that third argument should be interpreted as the root value or as the context.

@sheerun
Copy link

sheerun commented Apr 15, 2016

I'm all for changing api to options object

@leebyron
Copy link
Contributor

leebyron commented May 7, 2016

I think this is a good idea, but am curious how it would work. Right now the first argument to graphql is schema which itself is an object. We would just have to be quite careful to ensure such a change was non breaking.

@taion
Copy link
Contributor Author

taion commented May 7, 2016

I think the idea would be that this change would in fact be breaking (or maybe we can check for various properties on the object), but it would allow future changes like adding context as in 0.5.0 to be non-breaking.

@SunnyGurnani
Copy link

This should really be done otherwise we will keep breaking the API's

@b-barry
Copy link

b-barry commented Sep 29, 2016

After going through this issue, I would like to propose the solution below.
First, I create a new Object type for Object as the argument to graphql()

  type ObjectArgumentGraphql{
    schema: GraphQLSchema,
    requestString: string,
    rootValue?: mixed,
    contextValue?: mixed,
    variableValues?: ?{[key: string]: mixed},
    operationName?: ?string
  }

Then rename the first argument schema to options ( at the moment I don't find a real good name so if you have some idea, it is will be great if you can share it :) ). This argument will use the Union type system. They will have type GraphQLSchema or ObjectArgumentGraphql.
And based on the type of the first argument, I can determine if you have to destructure or not the argument to provide to the real "graph function" .

export function graphql(
  options: GraphQLSchema | ObjectArgumentGraphql ,
  requestString: ? string,
  rootValue?: mixed,
  contextValue?: mixed,
  variableValues?: ?{[key: string]: mixed},
  operationName?: ?string
): Promise<GraphQLResult> {

  if(typeof options === 'ObjectArgumentGraphql'){
    let { schema, requestString, rootValue , contextValue , variableValues, operationName } = options;
    return graph( schema, requestString, rootValue , contextValue , variableValues, operationName);
  }

  return graph( schema, requestString, rootValue , contextValue , variableValues, operationName);
}

function graph(
  schema: GraphQLSchema ,
  requestString:  string,
  rootValue?: mixed,
  contextValue?: mixed,
  variableValues?: ?{[key: string]: mixed},
  operationName?: ?string
): Promise<GraphQLResult> {

  return new Promise(resolve => {
    const source = new Source(requestString || '', 'GraphQL request');
    const documentAST = parse(source);
    const validationErrors = validate(schema, documentAST);
    if (validationErrors.length > 0) {
      resolve({ errors: validationErrors });
    } else {
      resolve(
        execute(
          schema,
          documentAST,
          rootValue,
          contextValue,
          variableValues,
          operationName
        )
      );
    }
  }).catch(error => {
    return { errors: [ error ] };
  });
}

What do you think about it ?

@migueloller
Copy link

migueloller commented Sep 30, 2016

A sensible approach could be to make the change and when graphql is called take a look at the arguments. If the caller is using the old (multiple arguments) signature, simply log a deprecation warning.

Implementing this change would be quite simple since the first argument is easily identifiable (i.e., arg isntanceof GraphQLSchema).

graphql(
  schema,
  requestString,
  rootValue,
  contextValue,
  variableValues,
  operationName
); // console.warn(deprecationReason);

graphql({
  schema,
  requestString,
  rootValue,
  contextValue,
  variableValues,
  operationName
}); // 👍

It would be a very simple change and I'd be willing to make a PR if it's something @leebyron would consider merging.

EDIT: As everybody else has been commenting, this change would be very good because of two main reasons: (1) There is no specific argument order meaning that the developer could skip optional arguments (or the implementation could be simplified if it allows for optional arguments) and (2) as new arguments are added to the graphql function, changes are less likely to be breaking given that it will still take an object and the order doesn't matter.

@taion
Copy link
Contributor Author

taion commented Sep 30, 2016

IMO it'd make the most sense to just go ahead and break the API. It's what was done for context.

leebyron added a commit that referenced this issue May 18, 2017
As well as execute() and subscribe()

Closes #356
leebyron added a commit that referenced this issue May 18, 2017
As well as execute() and subscribe()

Closes #356
leebyron added a commit that referenced this issue May 18, 2017
As well as execute() and subscribe()

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

No branches or pull requests

7 participants