Discover how separating data reading and writing can save you hours of debugging and confusion!
Why Queries and mutations in NestJS? - Purpose & Use Cases
Imagine building a web app where you have to manually write separate code to fetch data and then write different code to update or delete that data every time a user interacts.
You have to handle all the database calls, check for errors, and update the UI yourself.
This manual approach is slow and repetitive.
It's easy to make mistakes like mixing up data fetching and updating logic.
Maintaining and scaling this code becomes a headache as your app grows.
Queries and mutations clearly separate data reading (queries) from data changing (mutations).
Frameworks like NestJS provide tools to define these cleanly, so your code is organized and easier to manage.
async function getUser() { return await db.findUser(); } async function updateUser() { await db.updateUser(); }@Query() getUser() { ... } @Mutation() updateUser() { ... }This separation lets you build apps that are easier to understand, test, and extend over time.
Think of an online store: queries fetch product lists, mutations handle adding items to the cart or placing orders.
Queries fetch data without changing it.
Mutations change data and can trigger updates.
Using them keeps your code clean and scalable.
Practice
Solution
Step 1: Understand the purpose of @Query
The @Query decorator marks a method as a GraphQL query, which fetches data without changing it.Step 2: Differentiate from @Mutation
@Mutation is used for methods that change data, so it is not correct here.Final Answer:
@Query -> Option AQuick Check:
Fetch data = @Query [OK]
- Confusing @Mutation with @Query
- Using @ResolveField for queries
- Thinking @Subscription fetches data
createUser in a NestJS GraphQL resolver?Solution
Step 1: Check decorator usage with return type
The correct syntax uses @Mutation with a function returning the GraphQL type, e.g., @Mutation(() => User).Step 2: Verify method name and decorator match
The method name is createUser, and it must be decorated with @Mutation, not @Query.Final Answer:
@Mutation(() => User)\ncreateUser() { /*...*/ } -> Option CQuick Check:
Mutation with return type syntax = @Mutation(() => User)\ncreateUser() { /*...*/ } [OK]
- Omitting the return type function in decorator
- Using @Query instead of @Mutation
- Adding empty parentheses without return type
getUser query is called?@Query(() => String)
getUser() {
return 'Alice';
}Solution
Step 1: Analyze the @Query return type and method
The method getUser returns the string 'Alice' and is decorated with @Query(() => String), matching the return type.Step 2: Determine the GraphQL response
GraphQL will return the string value "Alice" as the query result.Final Answer:
"Alice" -> Option BQuick Check:
Matching return type returns value correctly [OK]
- Expecting an error due to missing async
- Confusing return value with null or undefined
- Thinking GraphQL wraps string differently
@Mutation(() => Boolean)
async updateUser() {
this.userService.update();
return true;
}Solution
Step 1: Check async method and service call
The method is async but calls userService.update() without await, so the update may not complete before returning.Step 2: Understand the impact of missing await
Without await, the mutation returns true immediately, possibly before update finishes, causing unexpected behavior.Final Answer:
Missing await before userService.update() -> Option DQuick Check:
Async method must await async calls [OK]
- Ignoring missing await in async methods
- Confusing Boolean with boolean types
- Thinking async is not allowed in mutations
Solution
Step 1: Confirm correct decorator for data change
Since this method updates data, it must use @Mutation with the return type User.Step 2: Check argument decorator usage
The argument email is correctly decorated with @Args('email') to extract the argument from GraphQL input.Step 3: Verify method signature correctness
@Mutation(() => User) updateEmail(@Args('email') email: string) { return this.userService.updateEmail(email); } correctly combines @Mutation, return type, and @Args usage.Final Answer:
@Mutation(() => User) updateEmail(@Args('email') email: string) { return this.userService.updateEmail(email); } -> Option AQuick Check:
Mutation with @Args('email') and return type = @Mutation(() => User) updateEmail(@Args('email') email: string) { return this.userService.updateEmail(email); } [OK]
- Using @Query for mutations
- Omitting @Args decorator
- Using @Args() without argument name
Ready to prove it?
Pass the test and this pattern moves unknown
