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

Mutations for nested resources #221

Closed
xpepermint opened this issue Nov 5, 2015 · 10 comments
Closed

Mutations for nested resources #221

xpepermint opened this issue Nov 5, 2015 · 10 comments

Comments

@xpepermint
Copy link

@xpepermint xpepermint commented Nov 5, 2015

OK, mutations are queries for manipulating data. If so then my root query and root mutation tree should look similar and they both should allow nested fields (nested mutations). I was playing with this (using express-graphql) and it works.

Example:

// PUT /projects/:project_id/products/:id
mutation {
  findProject(id: 1) { // make sure that the project exists and we can access it before mutating data
    updateProduct(id: 1, name: "Foo") { // the resolve function receives a valid `project` as the first arg
      id
    }
  } 
}

Is this a valid example? Should mutations be nested like this? If no, how should I handle nested resources? I can not find any real-life example that would mutate nested resources. All examples define mutations only on the first level (fields on the root mutation).

@OlegIlyenko
Copy link
Contributor

@OlegIlyenko OlegIlyenko commented Nov 12, 2015

There is at the moment one big difference between query and mutation type. Root mutation fields are guaranteed to execute strictly sequentially even if you are returning promises as a result of the resolve method. Root query fields, as well as nested mutation fields, do not have this execution guarantee.

So in other words only root mutation fields are meant to be used for mutations (at least I interpret it like this). I guess it depends on your use-case. So maybe it still make sense to do mutations in the nested fields as long as execution order does not matter.

In many cases though the order of execution matters. I think this GH issue raises a valid concern. Since sequential execution is limited only to root mutation fields, all possible application mutations should be defined as fields directly in the mutation type. In big applications and schemas it can cause very big mutation type with many unrelated/independent fields. Also I see namespacing as a problem. Given this flat mutation structure, I don't see other way but to follow naming convention to group related mutations together, which I find suboptimal in my case. That said, as long a number of mutation fields is low, I guess it should be manageable. Polymorphic input types can definitely help in this respect (at least in my case).

@leebyron
Copy link
Contributor

@leebyron leebyron commented Nov 17, 2015

We do not support mutations at any level other than the top. In cases where we need to support more complex mutations that rely on more information, we implement that in the resolve() function of the mutation.

In this case, updateProduct's resolve() function should first ensure that the product ID is valid before performing the update and do whatever is reasonable in the case that no product by that ID was found - perhaps return an error.

@leebyron leebyron closed this Nov 17, 2015
@xpepermint
Copy link
Author

@xpepermint xpepermint commented Nov 17, 2015

@leebyron thanks!

@schickling
Copy link

@schickling schickling commented Feb 17, 2017

Thanks for bringing this up @xpepermint.

We at Graphcool have written a blog post about nested mutations and how to use them to improve DX. You can find it here: https://www.graph.cool/blog/improving-dx-with-nested-mutations-vietahx7ih

The schema design we're proposing looks like this:

image

@prozacgod
Copy link

@prozacgod prozacgod commented Mar 2, 2017

@schickling is createPost returning the 'post' type - the same as perhaps an expected query would return like getPost or a post object in the query.

If the result of createPost is the same type as the query of a post, could then the query of the author is independent of the results of the insert, as in I depending on implementation I could see where the author(data) in the result might not return the same author(data) as expected.

I totally understand why the graphql authors are being careful about their implementation, and some features that are requested, and the slowness of new features. This stuff hurts my head on a good day. AND it needs to be viable for many types of implementations.

@oney
Copy link

@oney oney commented Dec 24, 2017

I believe my package is the best way to achieve nested mutations.
Check it out https://github.com/oney/graphql-mutate

@tvvignesh
Copy link

@tvvignesh tvvignesh commented Dec 25, 2019

@leebyron Hi. I had a doubt. I read this issue and this blog post here: https://www.freecodecamp.org/news/beware-of-graphql-nested-mutations-9cdb84e062b5/ on nested mutations. The following is an example on how I am using it to organize my mutations into appropriate groups.

Will I face any issue while doing this? I am not relying on the parent's value in the child but I am just using them as a way to organize my mutations. Is this valid and okay to use?

Sample Schema:

type Mutation {
    User: UserOps
    Posts: PostOps
}

type UserOps {
    createUsers(users: [CreateUserInput]): [UserSchema]
}

Sample query

mutation createUsers($userObjList: [CreateUserInput]) {
  User {
    createUsers(users: $userObjList) {
      name
      dob
      id
    }
  }
}

@schickling The link is broken. Thought I would let you know.

Thanks.

@dncrews
Copy link

@dncrews dncrews commented Jan 3, 2020

@tvvignesh

We do not support mutations at any level other than the top

I would echo this and encourage you not to do what you're trying to do. There are better ways to namespace and keep organized than by breaking the spec in this way.

@tvvignesh
Copy link

@tvvignesh tvvignesh commented Jan 3, 2020

@dncrews Regarding "better ways to namespace", any ideas on how we can do that (not from a developer perspective, but for users who are actually exploring the GraphQL documentation through the explorer)

@dncrews
Copy link

@dncrews dncrews commented Jan 4, 2020

I'm not sure where I should be answering this question, since you're asking it on both threads, but since OP had a different question than this one, I'm putting my answer on your other issue: apollographql/apollo-server#3635 (comment)

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

Successfully merging a pull request may close this issue.

None yet
8 participants