Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

graphql, how to design input type when there are "add" and "update" mutation?

Here are my requirements:

  1. "add" mutation, every field(or called scalar) of BookInput input type should have additional type modifiers "!" to validate the non-null value. Which means when I add a book, the argument must have title and author field, like {title: "angular", author: "novaline"}

  2. "update" mutation, I want to update a part of fields of the book, don't want to update whole book(MongoDB document, And, I don't want front-end to pass graphql server a whole big book mutation argument for saving bandwidth). Which means the book argument can be {title: "angular"} or {title: "angular", author: "novaline"}.

Here are my type definitions:

const typeDefs = `
  input BookInput {
    title: String!
    author: String!
  }

  type Book {
    id: ID!
    title: String!
    author: String!
  }

  type Query {
    books: [Book!]!
  }

  type Mutation{
    add(book: BookInput!): Book
    update(id: String!, book: BookInput!): Book
  }
`;

For now, "add" mutation works fine. But "update" mutation cannot pass the non-null check if I pass {title: "angular"} argument

Here is a mutation which does not pass the non-null check, lack of "author" field for BookInput input type.

mutation {
  update(id: "1", book: {title: "angular"}) {
    id
    title
    author
  }
}

So, graphql will give me an error:

{
  "errors": [
    {
      "message": "Field BookInput.author of required type String! was not provided.",
      "locations": [
        {
          "line": 2,
          "column": 24
        }
      ]
    }
  ]
}

How do I design the BookInput input type? Don't want to define addBookInput and updateBookInput. It's duplicated.

like image 829
slideshowp2 Avatar asked Jul 25 '18 11:07

slideshowp2


People also ask

How do you use update mutations in GraphQL?

Update mutations take filter as an input to select specific objects. You can specify set and remove operations on fields belonging to the filtered objects. It returns the state of the objects after updating. Note Executing an empty remove {} or an empty set{} doesn't have any effect on the update mutation.

Can you update data with GraphQL?

In GraphQL, you insert, update or delete data with mutations. A Mutation is a GraphQL Operation that allows you to insert new data or modify the existing data on the server-side. You can think of GraphQL Mutations as the equivalent of POST , PUT , PATCH and DELETE requests in REST.


1 Answers

A very common pattern is to have separate input types for each mutation. You may also want to create one mutation query per operation. Perhaps something like this:

const typeDefs = `
  input AddBookInput {
    title: String!
    author: String!
  }

  input UpdateBookInput {
    # NOTE: all fields are optional for the update input 
    title: String
    author: String
  }

  type Book {
    id: ID!
    title: String!
    author: String!
  }

  type Query {
    books: [Book!]!
  }

  type Mutation{
    addBook(input: AddBookInput!): Book
    updateBook(id: String!, input: UpdateBookInput!): Book
  }
`;

Some people also like to include the update ID as part of the update input:

const typeDefs = `
  input AddBookInput {
    title: String!
    author: String!
  }

  input UpdateBookInput {
    # NOTE: all fields, except the 'id' (the selector), are optional for the update input 
    id: String!
    title: String
    author: String
  }

  type Book {
    id: ID!
    title: String!
    author: String!
  }

  type Query {
    books: [Book!]!
  }

  type Mutation{
    addBook(input: AddBookInput!): Book
    updateBook(input: UpdateBookInput!): Book
  }
`;

Finally, you may want to use a 'payload' type for the return type - for added flexibility (gives you more wiggle room to change the return type later without breaking your API):

const typeDefs = `
  input AddBookInput {
    title: String!
    author: String!
  }

  input UpdateBookInput {
    # NOTE: all fields, except the 'id' (the selector), are optional for the update input 
    id: String!
    title: String
    author: String
  }

  type Book {
    id: ID!
    title: String!
    author: String!
  }

  type AddBookPayload {
    book: Book!
  }

  type UpdateBookPayload {
    book: Book!
  }

  type Query {
    books: [Book!]!
  }

  type Mutation{
    addBook(input: AddBookInput!): AddBookPayload!
    updateBook(input: UpdateBookInput!): UpdateBookPayload!
  }
`;

Hope this helps!

like image 72
Mikael Lirbank Avatar answered Oct 02 '22 18:10

Mikael Lirbank