📖 Scenario: You are building a simple GraphQL API for a bookstore. The data is stored in a SQL database. You want to create resolvers that fetch data from the SQL database when a client queries the GraphQL API.
🎯 Goal: Create SQL database resolvers in GraphQL that fetch book data from a SQL database table called books. You will set up the initial data structure, add configuration for the database connection, write the core resolver logic, and complete the resolver setup.
📋 What You'll Learn
Create a GraphQL resolver function named getBooks that queries the books table
Add a configuration variable dbClient to connect to the SQL database
Write the SQL query inside the resolver to select all columns from books
Complete the resolver export so it can be used in the GraphQL server
💡 Why This Matters
🌍 Real World
GraphQL APIs often need to fetch data from SQL databases. Writing resolvers that query SQL tables is a common task in backend development.
💼 Career
Backend developers and full-stack engineers frequently write database resolvers to connect GraphQL APIs with SQL databases, enabling efficient data retrieval and manipulation.
Progress0 / 4 steps
1
DATA SETUP: Create the resolver function skeleton
Create a function called getBooks that takes parent, args, and context as parameters. The function should be asynchronous and return an empty array for now.
GraphQL
Hint
Define an async function named getBooks with the parameters parent, args, and context. Return an empty array inside.
2
CONFIGURATION: Add the database client variable
Add a constant variable called dbClient that represents the SQL database client connection. For this example, set it to { query: async () => ({ rows: [] }) } to simulate a database client.
GraphQL
Hint
Create a constant dbClient that has a query method returning an object with an empty rows array.
3
CORE LOGIC: Write the SQL query inside the resolver
Inside the getBooks function, use dbClient.query to run the SQL query SELECT * FROM books;. Await the result and return the rows property from the query result.
GraphQL
Hint
Use await dbClient.query('SELECT * FROM books;') and return the rows from the result.
4
COMPLETION: Export the resolver function
Add an export statement that exports an object with a Query property. Inside Query, assign the getBooks function to the books field.
GraphQL
Hint
Export an object named resolvers with a Query property that maps books to getBooks.
Practice
(1/5)
1. What is the main role of SQL database resolvers in a GraphQL server?
easy
A. To format the GraphQL query results into JSON
B. To define the GraphQL schema types and fields
C. To handle user authentication and authorization
D. To fetch or modify data in the SQL database based on GraphQL queries or mutations
Solution
Step 1: Understand the purpose of resolvers
Resolvers are functions that connect GraphQL queries or mutations to the actual data source, here an SQL database.
Step 2: Identify the role in data fetching and modification
Resolvers run SQL commands to get or change data as requested by the GraphQL operations.
Final Answer:
To fetch or modify data in the SQL database based on GraphQL queries or mutations -> Option D
Quick Check:
Resolvers connect queries to SQL data [OK]
Hint: Resolvers link GraphQL queries to SQL commands [OK]
Common Mistakes:
Confusing resolvers with schema definitions
Thinking resolvers handle authentication
Assuming resolvers format output only
2. Which of the following is the correct way to define a resolver function for a GraphQL query named getUser that fetches user data from an SQL database?
easy
A. const resolvers = { Query: { getUser: () => db.query('SELECT * FROM users') } };
B. const resolvers = { Mutation: { getUser: () => db.query('SELECT * FROM users') } };
C. const resolvers = { Query: { getUser: 'SELECT * FROM users' } };
D. const resolvers = { getUser: () => db.query('SELECT * FROM users') };
Solution
Step 1: Identify the correct resolver structure for a query
Resolvers for queries are defined inside the Query object with function values.
Step 2: Check the syntax for calling the database query
The resolver should be a function returning the result of db.query with the SQL command string.
Final Answer:
const resolvers = { Query: { getUser: () => db.query('SELECT * FROM users') } }; -> Option A
Quick Check:
Query resolvers are functions inside Query object [OK]
Hint: Query resolvers go inside Query object as functions [OK]
Common Mistakes:
Placing query resolver inside Mutation
Assigning SQL string directly instead of a function
Defining resolver outside Query or Mutation objects
3. Given the resolver below, what will be the output when the GraphQL query { getUserById(id: 2) { name } } is executed?
Hint: Never insert variables directly into SQL strings [OK]
Common Mistakes:
Ignoring SQL injection vulnerability
Thinking backticks cause errors
Expecting mutation in Query object
5. You want to write a resolver that fetches all orders for a user, but only if the user is active. The SQL tables are users(id, active) and orders(id, user_id, total). Which resolver implementation correctly enforces this condition efficiently?
hard
A. const resolvers = { Query: { userOrders: (_, args) => db.query(`SELECT * FROM orders WHERE user_id = ${args.userId}`) } };
B. const resolvers = { Query: { userOrders: (_, args) => { const user = db.query(`SELECT * FROM users WHERE id = ${args.userId}`); if (user.active) { return db.query(`SELECT * FROM orders WHERE user_id = ${args.userId}`); } else { return []; } } } };
C. const resolvers = { Query: { userOrders: (_, args) => db.query(`SELECT * FROM orders WHERE user_id = ${args.userId} AND EXISTS (SELECT 1 FROM users WHERE id = ${args.userId} AND active = TRUE)`) } };
D. const resolvers = { Query: { userOrders: (_, args) => db.query(`SELECT * FROM users WHERE id = ${args.userId} AND active = TRUE`) } };
Solution
Step 1: Understand the requirement
Fetch orders only if the user is active, combining the check and data fetch efficiently.
Step 2: Evaluate each option
const resolvers = { Query: { userOrders: (_, args) => db.query(`SELECT * FROM orders WHERE user_id = ${args.userId} AND EXISTS (SELECT 1 FROM users WHERE id = ${args.userId} AND active = TRUE)`) } }; uses a single SQL query with EXISTS to check user active status and fetch orders in one call, which is efficient and correct. const resolvers = { Query: { userOrders: (_, args) => { const user = db.query(`SELECT * FROM users WHERE id = ${args.userId}`); if (user.active) { return db.query(`SELECT * FROM orders WHERE user_id = ${args.userId}`); } else { return []; } } } }; fetches user first then orders separately, causing multiple queries and possible async issues. const resolvers = { Query: { userOrders: (_, args) => db.query(`SELECT * FROM orders WHERE user_id = ${args.userId}`) } }; fetches orders without checking user active status. const resolvers = { Query: { userOrders: (_, args) => db.query(`SELECT * FROM users WHERE id = ${args.userId} AND active = TRUE`) } }; fetches user data only, not orders.
Final Answer:
const resolvers = { Query: { userOrders: (_, args) => db.query(`SELECT * FROM orders WHERE user_id = ${args.userId} AND EXISTS (SELECT 1 FROM users WHERE id = ${args.userId} AND active = TRUE)`) } }; -> Option C
Quick Check:
Single query with EXISTS enforces condition efficiently [OK]
Hint: Use EXISTS in SQL to combine condition and fetch in one query [OK]
Common Mistakes:
Running multiple queries instead of one
Not checking user active status before fetching orders
Returning user data instead of orders
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.