Type-graphql: An example of the nested mutation

Created on 20 Apr 2018  路  3Comments  路  Source: MichalLytek/type-graphql

Hi!
First of all, great library, thanks a lot!
I'm currently building a graphql API and want to make it as generic as possible.
I have many objects and want to have same generic mutations for each object type (create, update and delete). At the moment, I have implemented a resolver for each of my object types, each with it's methods so I can update my objects like this:

mutation {
   addBook(input: $bookInput) {
     id
  }
}

```graphql
mutation {
addUser(input: $userInput) {
id
}
}

```graphql
mutation {
   addProject(input: $projectInput) {
     id
  }
}

Is there a way to instead nest the mutation under the object name, like so

mutation {
   book 
     add(input: $bookInput) {
       id
    }
}

```graphql
mutation {
user
add(input: $userInput) {
id
}
}

```graphql
mutation {
   project 
     add(input: $projectInput) {
       id
    }
}

In this case I could implement the basic mutations (add, update and delete) in the base resolver class and just inherit from it in object-specific resolvers, maybe use some decorators to override the input types.

Question Solved

Most helpful comment

@limenutt
I've done some research and this pattern doesn't match semantically to the mutation constraints.

In GraphQL spec, project, book or user would have to be GraphQLOutputType, in this case ObjectType. So add, delete, edit would have to be object's field which resolvers just takes arguments.

So the problem is that clients could do parallel mutation by e.g.:

mutation {
  project {
    add(input: { name: "test2" }) {
      id
    }
    edit(input: { id: 2, name: "test2 edit" }) {
      id
    }
    delete(id: 2) {
      id
    }
  }
}

And as they're resolvers are attached to ObjectType, they behave like the query, so they are executed in parallel.

But by design, mutation are changing the app/server state so they have to be reliable.
When client sends multiple mutation, they are executed sequentially, which wouldn't be true in the nested "mutation" example.

So I think that this approach to designing schema doesn't give any improvements to the clients, just have negative impacts. As you will have generic service for common business logic, it's easy to create separate one-line resolvers with mutations like addUser, editBook, etc.

If this answer exhaust the topic, please close the issue 馃槈

All 3 comments

Nested mutations sound nice, I haven't thought about it but it seems possible to do.

However, about the resolver inheritance part:

I could implement the basic mutations (add, update and delete) in the base resolver class and just inherit from it in object-specific resolvers

We've already discussed it:
https://github.com/19majkel94/type-graphql/issues/47
And it's just better to have less magic and inheritance problem. Decorator duplication is not an issue, it's like a documentation for your API. You can move your common CRUD logic to generic service and inject the specific extended services per entity type.

@limenutt
I've done some research and this pattern doesn't match semantically to the mutation constraints.

In GraphQL spec, project, book or user would have to be GraphQLOutputType, in this case ObjectType. So add, delete, edit would have to be object's field which resolvers just takes arguments.

So the problem is that clients could do parallel mutation by e.g.:

mutation {
  project {
    add(input: { name: "test2" }) {
      id
    }
    edit(input: { id: 2, name: "test2 edit" }) {
      id
    }
    delete(id: 2) {
      id
    }
  }
}

And as they're resolvers are attached to ObjectType, they behave like the query, so they are executed in parallel.

But by design, mutation are changing the app/server state so they have to be reliable.
When client sends multiple mutation, they are executed sequentially, which wouldn't be true in the nested "mutation" example.

So I think that this approach to designing schema doesn't give any improvements to the clients, just have negative impacts. As you will have generic service for common business logic, it's easy to create separate one-line resolvers with mutations like addUser, editBook, etc.

If this answer exhaust the topic, please close the issue 馃槈

Thank you, I appreciate your prompt thorough response!
Yes, I think your argument makes sense.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

memark picture memark  路  3Comments

Asim13se picture Asim13se  路  3Comments

itsgracian picture itsgracian  路  3Comments

MichalLytek picture MichalLytek  路  3Comments

tongtwist picture tongtwist  路  3Comments