GraphQL fragments

One of the scripts that builds and deploys datasette.io uses a GraphQL query to retrieve information from GitHub about the repositories used for the various Datasette tools and plugins.

That query was very big - over 4,000 lines long!

That's because it was shaped like this:

{
  repo_0: repository(name: "datasette-query-history", owner: "bretwalker") {
    id
    nameWithOwner
    createdAt
    openGraphImageUrl
    usesCustomOpenGraphImage
    defaultBranchRef {
      target {
        oid
      }
    }
    repositoryTopics(first: 100) {
      totalCount
      nodes {
        topic {
          name
        }
      }
    }
    openIssueCount: issues(states: [OPEN]) {
      totalCount
    }
    closedIssueCount: issues(states: [CLOSED]) {
      totalCount
    }
    releases(last: 1) {
      totalCount
      nodes {
        tagName
      }
    }
  }
  # ...
  repo_137: repository(name: "yaml-to-sqlite", owner: "simonw") {
    id
    nameWithOwner
    createdAt
    openGraphImageUrl
    usesCustomOpenGraphImage
    defaultBranchRef {
      target {
        oid
      }
    }
    repositoryTopics(first: 100) {
      totalCount
      nodes {
        topic {
          name
        }
      }
    }
    openIssueCount: issues(states: [OPEN]) {
      totalCount
    }
    closedIssueCount: issues(states: [CLOSED]) {
      totalCount
    }
    releases(last: 1) {
      totalCount
      nodes {
        tagName
      }
    }
  }
}

That block was repeated for every repository - 138 in total!

I figured there was likely a way to do this more efficiently, and it turns out there is: GraphQL fragments.

Here's that example query rewritten to use fragments instead:

fragment repoFields on Repository {
  id
  nameWithOwner
  createdAt
  openGraphImageUrl
  usesCustomOpenGraphImage
  defaultBranchRef {
    target {
      oid
    }
  }
  repositoryTopics(first: 100) {
    totalCount
    nodes {
      topic {
        name
      }
    }
  }
  openIssueCount: issues(states: [OPEN]) {
    totalCount
  }
  closedIssueCount: issues(states: [CLOSED]) {
    totalCount
  }
  releases(last: 1) {
    totalCount
    nodes {
      tagName
    }
  }
}
{
  repo_0: repository(name: "datasette-query-history", owner: "bretwalker") {
    ...repoFields
  }
  repo_137: repository(name: "yaml-to-sqlite", owner: "simonw") {
    ...repoFields
  }
}

Now each additional repo added to the query is only 3 extra lines of GraphQL, not 30!

Created 2022-09-30T15:47:20-07:00 · Edit