Skip to main content
GraphQL Basics
CHAPTER 10 Beginner

GraphQL Resolvers Explained

Updated: May 13, 2026
25 min read

# CHAPTER 10

GraphQL Resolvers Explained

1. Introduction

Up until now, we have focused heavily on the "frontend" of GraphQL—writing schemas, executing queries, and passing variables. But a schema is just an empty promise. How does the server actually fulfill that promise? Where does the data come from? The answer is Resolvers. Resolvers are the beating heart of a GraphQL server. In this chapter, we will learn what resolvers are, how they connect to your database (like MySQL), and how they resolve complex nested queries field by field.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Define what a Resolver function is in GraphQL.
  • Understand the 4 standard arguments passed to every resolver ($root, $args, $context, $info).
  • Write resolver functions in PHP to fetch data from an array or database.
  • Explain the execution flow of a GraphQL query on the server.

3. Beginner-Friendly Explanation

Imagine you are at a large library. You hand the librarian a list (the Query):
  1. 1. Give me a book on Space.
  1. 2. Give me the author's name.

The Schema is the rulebook that says the library actually has books on space. The Resolver is the librarian physically walking to the shelf, finding the book, getting the data, and bringing it back to the desk.

Every single field in a GraphQL query has a dedicated Resolver (librarian) associated with it. When you ask for book, the Book Resolver goes to the database. When you ask for author inside the book, the Author Resolver looks at the book, sees the author ID, and goes to find the author's details.

4. Real-World Examples

  • Fetching from MySQL: A resolver for getUser(id: 1) runs a SQL query: SELECT * FROM users WHERE id = 1, and returns the row.
  • Fetching from a Third-Party API: A resolver for currentWeather might use cURL to fetch data from the OpenWeatherMap REST API and return the JSON.
  • Calculated Fields: A resolver for fullName might take the firstName and lastName from the database, concatenate them, and return the combined string.

5. Detailed Code Examples

Let's look at how resolvers are written using PHP (via webonyx/graphql-php).

The Scenario: A simple query fetching a user.

graphql
12345
query {
  user(id: 1) {
    name
  }
}

The PHP Resolvers:

php
1234567891011121314151617181920212223242526272829
<?php
// Mock Database
$usersDB = [
    1 => [&#039;name' => 'Alice', 'email' => 'alice@example.com'],
    2 => [&#039;name' => 'Bob', 'email' => 'bob@example.com']
];

$queryType = new ObjectType([
    &#039;name' => 'Query',
    &#039;fields' => [
        &#039;user' => [
            &#039;type' => $userType,
            &#039;args' => [
                &#039;id' => Type::nonNull(Type::int())
            ],
            // THIS IS THE RESOLVER FUNCTION
            &#039;resolve' => function ($root, $args, $context, $info) use ($usersDB) {
                $userId = $args[&#039;id'];
                
                // Fetch data (could be a MySQL PDO query here)
                if (isset($usersDB[$userId])) {
                    return $usersDB[$userId];
                }
                return null;
            }
        ]
    ]
]);
?>

6. The 4 Resolver Arguments

Every resolver function in the world (whether in PHP, Node, Python, etc.) receives four specific arguments:
  1. 1. $root (or $parent): The result of the previous resolver. If resolving the author of a post, $root contains the post data.
  1. 2. $args: The arguments passed in the query (e.g., id: 1).
  1. 3. $context: An object shared across all resolvers. Used for storing the logged-in User's ID, database connections, or authentication tokens.
  1. 4. $info: Advanced details about the query's execution state (rarely used by beginners).

7. Resolving Nested Queries

How does GraphQL handle nesting? Resolvers execute in a tree structure.
graphql
12345678
query {
  post(id: 5) {     # 1. Post Resolver runs
    title           # 2. Default resolver extracts 'title' from Post data
    author {        # 3. Author Resolver runs, using Post data as $root
      name          # 4. Default resolver extracts 'name' from Author data
    }
  }
}

8. Default Resolvers

You might wonder: "Do I have to write a resolver for every single string and integer field?" No. GraphQL libraries have "Default Resolvers." If your user resolver returns a PHP associative array ['name' => 'Alice'], and the query asks for name, the default resolver automatically looks for the array key name and returns it. You only write custom resolvers for complex data fetching or relationships.

9. Best Practices

  • Keep Resolvers Thin: Do not put complex business logic inside the resolver. The resolver should only extract $args, call a dedicated service class (e.g., UserService->getUserById($id)), and return the result.
  • Use Context for Dependency Injection: Pass your PDO database connection and authenticated user session into the $context object so all resolvers can access them without using global variables.

10. Common Mistakes

  • The N+1 Problem: This is the most famous GraphQL pitfall. If you query 100 posts, and each post resolves its author, the Author resolver might execute a SQL SELECT 100 times. We will discuss solving this (using DataLoaders) in later chapters.
  • Returning the Wrong Type: If the Schema says a field returns an Int, but your resolver returns a string "42", GraphQL will throw an execution error.

11. Mini Exercises

  1. 1. Which resolver argument would you use to get the search term typed by a user?
  1. 2. Which resolver argument would you use to check if a user is logged in?
  1. 3. What is the $root argument used for?

12. Coding Challenges

Challenge 1: Write a mock PHP resolver function for a totalUsers field. The resolver does not need any arguments. It should simply return the integer 150 representing a SELECT COUNT(*) from a database.

13. MCQs with Answers

Question 1

What is the primary job of a Resolver in GraphQL?

Question 2

Which argument in a resolver function contains the values passed by the client (like an ID or search term)?

Question 3

Do you need to write a custom resolver function for a simple String field like username if it's already in the database array?

14. Interview Questions

  • Q: Explain the $root (or parent) argument in a resolver. Give an example of when it is used.
  • Q: What kind of information should be stored in the $context object?
  • Q: What happens if a resolver returns null for a field marked as Non-Null (!) in the schema?

15. FAQs

Q: Can a resolver connect to multiple databases? A: Yes! A single GraphQL query can have one resolver fetching data from MySQL, another from MongoDB, and a third from an external REST API. The frontend client has no idea; it just sees one unified JSON response.

Q: Are resolvers executed synchronously or asynchronously? A: In Node.js, they are asynchronous (Promises). In standard PHP, execution is synchronous, though libraries like webonyx support asynchronous patterns using Promises for advanced use cases.

16. Summary

In this chapter, we lifted the hood on the GraphQL server to explore Resolvers. We learned that every field in a schema is backed by a resolver function. We explored the four core arguments passed to resolvers: $root for relational data, $args for client inputs, $context for global state (like auth/databases), and $info. Finally, we saw how GraphQL elegantly delegates data fetching by executing resolvers in a tree structure.

17. Next Chapter Recommendation

We touched briefly on how resolvers handle relationships. Now it is time to fully understand how GraphQL handles deeply connected data. Proceed to Chapter 11: Nested Queries and Relationships to explore parent-child relationships and relational database querying in a graph.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·