Here are my requirements:
"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"}
"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.
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.
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.
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With