Introspecting operations

In the previous section we added a new field to fetch the latest episodes and we also added the ability of fetching the podcast information for every episode.

In this section we'll see how we could use the information about the GraphQL request to optimize our data fetching.

Introspecting the GraphQL request

When running the following GraphQL query:

{
  latestEpisodes {
    title
    podcast {
      title
    }
  }
}

we hit the n+1 problem. We are fetching the latest episodes and then for every episode we are fetching the podcast information.

We can solve this problem by using the information about the GraphQL request to fetch the data in a single query.

Strawberry provides information about the GraphQL request in the info argument of the resolver. Let's update our previous resolver to use this information:

from typing import List, Optional

import strawberry
from strawberry.types import Info

from api.pagination.types import Connection, Edge, PageInfo
from api.views import Context
from db import data

from .types import Episode, Podcast


@strawberry.type
class PodcastsQuery:
    # ...

    @strawberry.field
    async def latest_episodes(self, info: Info[Context, None], last: int = 5) -> List[Episode]:
        if last > 50:
            raise ValueError("last must be less than 50")

        current_selected_field = info.selected_fields[0]
        selected_fields = [
            selection.name for selection in current_selected_field.selections
        ]

        if "podcast" in selected_fields:
            # prefetch podcasts
            ...

        episodes = await data.find_latest_episodes(last=last)

        return [Episode.from_db(episode) for episode in episodes]

In the previous code we are checking if the podcast field is selected in the GraphQL request. We aren't really doing anything with the information yet, but you can see how we could pass this information down to find_latest_episodes and use django's prefetching capabilities to optimize the data fetching.

You could also use the information about the request to optimize the query on the individual field level. The only issue with this approach is that you are tying your API to the database and you need to make sure to reflect changes in the database in your API.

Another way to solve this problem is to use a dataloader. We'll see how we can use dataloaders in the next section.