Lesson 2
Handling More Complex Data Queries
Introduction And Context Setting

Welcome to the lesson on "Handling More Complex Data Queries" as part of the "Comprehensive Intro to GraphQL in TypeScript" course. In this lesson, we'll expand on what we learned about mutations in the previous lesson. We'll focus on setting up nested queries in GraphQL to handle more intricate relationships between data, specifically authors and books.

Defining The Schema With Nested Queries

To handle nested queries, we need a schema that represents our data types and their relationships.

  1. Define Data Types

    We'll create Author and Book types with fields that reference each other:

    TypeScript
    1const typeDefs = gql` 2 type Author { 3 id: ID! 4 name: String! 5 books: [Book] 6 } 7 8 type Book { 9 id: ID! 10 title: String! 11 author: Author 12 } 13 14 type Query { 15 books: [Book] 16 authors: [Author] 17 } 18`;
    • Author has fields id, name, and books, which is an array of Book.
    • Book has fields id, title, and an author, which is of type Author.
  2. Sample Data

    Define some sample data to work with:

    TypeScript
    1const authors = [ 2 { id: '1', name: 'J.R.R. Tolkien' }, 3 { id: '2', name: 'J.K. Rowling' } 4]; 5 6const books = [ 7 { id: '1', title: 'The Hobbit', author: '1' }, 8 { id: '2', title: 'Harry Potter', author: '2' } 9];

    This data will be used to simulate a small library.

Implementing Resolvers For Nested Queries

Resolvers are responsible for fetching the data defined in your schema.

  1. Define Resolvers

    Here's how you can write resolvers to handle nested queries:

    TypeScript
    1const resolvers = { 2 Query: { 3 books: () => books, 4 authors: () => authors 5 }, 6 Book: { 7 author: (book: any) => authors.find(author => author.id === book.author) 8 }, 9 Author: { 10 books: (author: any) => books.filter(book => book.author === author.id) 11 } 12};
    • The Query resolvers return the sample data for books and authors.
    • The Book resolver finds the author of a given book.
    • The Author resolver filters books written by a given author.
  2. Initialize Apollo Server

    Combine the schema and resolvers to set up the server:

    TypeScript
    1const server = new ApolloServer({ typeDefs, resolvers }); 2 3server.listen().then(({ url }: { url: string }) => { 4 console.log(`🚀 Server ready at ${url}`); 5});

    When you run your server.ts file, it should print:

    Plain text
    1🚀 Server ready at http://localhost:4000/
Testing The Nested Queries

Now that your server is up and running let's test the nested queries using a real-world example.

  1. Define The Query

    In a file called run.ts, write a query to fetch books and their authors:

    TypeScript
    1import fetch from 'node-fetch'; 2 3const fetchBooksAndAuthors = async () => { 4 const query = ` 5 query { 6 books { 7 title 8 author { 9 name 10 } 11 } 12 authors { 13 name 14 books { 15 title 16 } 17 } 18 } 19 `; 20 21 const url = 'http://localhost:4000/'; 22 23 try { 24 const response = await fetch(url, { 25 method: 'POST', 26 headers: { 27 'Content-Type': 'application/json', 28 }, 29 body: JSON.stringify({ query }), 30 }); 31 const data = await response.json(); 32 console.log(JSON.stringify(data, null, 2)); 33 } catch (error) { 34 console.error('Error:', error); 35 } 36}; 37 38fetchBooksAndAuthors();
  2. Run The Query

    Running this function should give you the following output:

    JSON
    1{ 2 "data": { 3 "books": [ 4 { 5 "title": "The Hobbit", 6 "author": { 7 "name": "J.R.R. Tolkien" 8 } 9 }, 10 { 11 "title": "Harry Potter", 12 "author": { 13 "name": "J.K. Rowling" 14 } 15 } 16 ], 17 "authors": [ 18 { 19 "name": "J.R.R. Tolkien", 20 "books": [ 21 { 22 "title": "The Hobbit" 23 } 24 ] 25 }, 26 { 27 "name": "J.K. Rowling", 28 "books": [ 29 { 30 "title": "Harry Potter" 31 } 32 ] 33 } 34 ] 35 } 36}

    This confirms the server correctly handles your nested queries and returns the expected data.

Summary And Next Steps

In this lesson, you've learned to handle more complex data queries in GraphQL by setting up nested queries with Apollo Server. You've defined a schema with nested types, implemented resolvers, and tested your queries.

Now, it's time to practice what you've learned. Head over to the practice exercises to solidify your understanding. Try experimenting with more complex queries and relationships to get a deeper grasp of handling data in GraphQL.

Congratulations on making it this far! Keep practicing to reinforce your newfound skills.

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.