GraphQL info in a query resolver

GraphQL is one of the most widely used query and manipulation languages for APIs. It is a great alternative to REST APIs due to various advantages. I have worked on various products that used GraphQL as a middleware; developed in TypeScript as well as Python. During those implementations, I wanted to optimize my changes for better overall performance. This article describes a use case for GraphQL info in a query resolver to achieve some of those optimizations

Prerequisites

  • Understanding of web APIs and its role in a web architecture
  • Understanding of GraphQL fundamentals
  • Experience implementing GraphQL API in at least one programming language

info Object

GraphQL query resolver receives four parameters; obj (root or parent), args, context and info. The info object holds details related to the current query. The structure of info object is as shown below

GraphQL info object type GraphQLResolveInfo
info Object type GraphQLResolveInfo

We will be utilizing fieldNodes values from the info object in the use case below

Use case: Optimize back-end SQL queries

The most common architecture, with GraphQL as middleware, is web UI querying information from a back-end. GraphQL integrates with a database service so when the UI invokes a GraphQL query, the resolver retrieves the details from the database via SQL query and returns it to the front-end. GraphQL info in query resolver can help to optimize this SQL queries

Consider the following GraphQL schema,

type Condo {
    id: ID!
    Type: String
    Address: String
    Owner: String
    Price: Float
    Bedrooms: Int
    Bathrooms: Float
    Parking: String
    YearBuilt: Int
    LotSize: Int
    PricePerSquareFeet: Float
    WalkScore: Int
}

type Query {
    condos: [Condo]
}Code language: CSS (css)

It is a simple query to request list of condos to display on a front-end. The resolver for the query connects to a database to retrieve the list,

sql_query = 'select * from condos'Code language: JavaScript (javascript)

Front-end can trigger the following query,

  {
    condos {
      Address
      Owner
      Price
    }
  }

This is very simple and straightforward so far. However, if you observe closely, front-end requests only Address, Owner and Price but the SQL query retrieves all the field values for the records. This can have significant impact when you have records with large fields set; every database retrieval will include this large fields set while front-end only requires sub-set of the fields. This is where info parameter can help. If you parse the info object in the resolver and look at fieldNodes, it contains the selected fields. The screenshots below are showing info object for the above GraphQL query in Graphene

info object for a GraphQL query
first level field of the query, condos
info object for a GraphQL query
second level fields for the query under selection set, 3 fields in this case
info object for a GraphQL query
Second level field for the query, Address

So, instead of retrieving all the database fields, the selected fields can be parsed in the resolver. This change will have a significant impact when you have a large fields set per record and GraphQL query has to return large record set to the front-end

fields = ','.join(node.name.value for node in info.field_nodes[0].selection_set.selections)
sql_query = 'select ' + fields + ' from condos'Code language: JavaScript (javascript)

You can implement more advanced parsing logic for the fields using recursive algorithm, so that all the fields with multiple depths can be retrieved to form more advanced SQL query