Typed Fields

Typed Fields offers a new content querying experience in the Nacelle Storefront API.

Understanding the Need for Typed Fields

In eCommerce projects, handling content data efficiently is pivotal for a seamless developer experience and performant shopping experience. Traditional querying methods for content often return more data than needed, making the process of retrieving specific pieces of content data somewhat cumbersome and inefficient.

The Typed Fields feature in the Nacelle Storefront GraphQL API directly addresses this challenge. Unlike other parts of the Nacelle's Storefront API schema that are designed around Nacelle's Canonical Data Model, the schema associated with Typed Fields for content data is entirely specific to each customer's unique content models. This feature allows developers to specify the exact type of content data they wish to retrieve, aligning precisely with their custom content models.

When working with the Nacelle Storefront GraphQL API, developers now have the choice between querying fields or typedFields to retrieve content data. This distinction is crucial for those aiming to harness the full power and flexibility of GraphQL their data requests.

While typedFields queries help reduce the response size, they incur a certain overhead to resolve nested fields. Carefully compare the performance of your typedFields queries to the corresponding fields queries to decide which one suits your needs better.

To learn more, contact your Nacelle CSM

Granular Data Queries with typedFields

Consider a typical content query in the Nacelle Storefront GraphQL API:

query MyContent {
  allContent(filter: { first: 1, entryDepth: 3 }) {
    edges {
      node {
        nacelleEntryId
        fields
      }
    }
  }
}

Let's explore the distinct advantages of using typedFields over fields:

The fields field provides a JSON blob of your content data. This means that when you query fields, you receive the entirety of your content data's fields in one go, regardless of whether you need all that information or not. The only control over the amount of data that's returned is via the entryDepth filter parameter, as described in Storefront GraphQL API - Content resolution.

By contrast, typedFields is designed to allow for more specific, granular data requests. Instead of receiving a large content payload that you then have to sift through, typedFields lets you specify exactly which pieces of content data you want.

For instance, suppose that you have an article-type content type that has a content field, a title field, and a relatedArticles field, among others. Let's say that we want to get the only want the content and title of each of the relatedArticles. With typedFields, you can directly request just those two pieces of information:

query MyRelatedArticles {
  allContent(filter: { first: 1, type: "article" }) {
    edges {
      node {
        nacelleEntryId
        typedFields {
          ... on ArticleFields {
            relatedArticles {
              nodes {
                typedFields {
                  ... on ArticleFields {
                    content
                    title
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Note the use of Inline Fragments to query the ArticleFields of interest. This is how we access specific content types within the top level of typedFields. Inline fragments allow us to query multiple types within a single typedFields query. For example, let's say that a page-type entry's sections field could contain heroBanner, sideBySide, or blogFeature-type content:

query MyPageSections {
  allContent(filter: { first: 1, type: "page" }) {
    edges {
      node {
        nacelleEntryId
        typedFields {
          ... on PageFields {
            sections {
              nodes {
                typedFields {
                  ... on HeroBannerFields {
                    title
                    subtitle
                  }
                  ... on SideBySideFields {
                    leftSide
                    rightSide
                  }
                  ... on BlogFeatureFields {
                    title
                    handle
                    description
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Exploring Typed Fields GraphQL types

When a Typed Fields schema for content exists for a given Nacelle space, a new field (typedFields: ContentTypedFields) will be available in the Content GraphQL type inside of an allContent query.

To explore the typedFields: ContentTypedFields GraphQL type, you can use the GraphQL Explorer built into the Nacelle Dashboard, or your favorite desktop GraphQL client. For example:

A screen capture of the Nacelle Dashboard's GraphQL Explorer demonstrates finding the `ContentTypedFields` type on the `Content` type from the Docs panel of the GraphQL Explorer

Filtering (ALPHA)

Not only does a Typed Fields schema contain the new ContentTypedFields, it also contains custom filters for the allContent query.

As before, you can use the GraphQL Explorer built into the Nacelle Dashboard, or your favorite desktop GraphQL client to explore all the filters. Start by looking for the allContent query.

These filters are specific to a typed fields type and include string filters and filters for other typed fields types:

type CustomArticleFields {
  author: CustomAuthor
  handle: String
  title: String
  topic: String
  pubslihed: Boolean
  views: Int
}

type CustomAuthorFields {
  firstName: String
  lastName: String
}

input CustomArticleFieldsFilterInput {
  author: CustomAuthorFieldsFilterInput
  handle: String
  title: String
}

input CustomAuthorFieldsFilterInput {
  firstName: String
  lastName: String
}

The CustomArticleFieldsFilterInput and CustomAuthorFieldsFilterInput can now be used with the allContent query to narrow down articles by author first and last name, handle and title:

query ContentQuery {
  allContent(
    customArticleFieldsFilter: {
      author: { firstName: "Jane", lastName: "Doe" }
      handle: "article-handle"
      title: "Article title"
    }
  ) {
    edges {
      node {
        typedFields {
          ... on CustomArticleFields {
            author {
              typedFields {
                firstName
                lastName
              }
            }
            handle
            title
          }
        }
      }
    }
  }
}

This query would only return the articles where the author's first and last name, the handle and the title match the filter parameters.

If need be, two filters can be used at the same time:

query ContentQuery {
  allContent(
    customArticleFieldsFilter: {
      author: { firstName: "Jane", lastName: "Doe" }
    }
    customAuthorFieldsFilter: { lastName: "Smith" }
  ) {
    edges {
      node {
        typedFields {
          ... on CustomArticleFields {
            author {
              typedFields {
                name
              }
            }
            handle
            title
          }
          ... on CustomAuthorFields {
            firstName
            lastName
          }
        }
      }
    }
  }
}

This query will return all articles written by Jane Doe and all authors with Smith as last name.

Notes

  • filtering is only applied if typedFields was queried for, i.e. it will not be applied if fields was queried for; this also means that you cannot include any custom filters in your fields queries (we use a simplified schema in that case to provide improved performance)
  • when a filter is applied, only content that satisfies all conditions is returned
  • when multiple filters are applied, the result is the union of all individual filter results
  • all string filters test for strict string equality
  • a filter is only applied if the corresponding type appears in the request (CustomAuthorFields - customAuthorFieldsFilter)

Working with Typed Fields in your code editor

For the ultimate Developer Experience with Typed Fields, we strongly recommend using GraphQL Codegen and GraphQL Config. In addition to improving the type safety of your project code, these tools also increase developer velocity by making your code editor aware of your GraphQL schema. This allows your code editor to suggest fields to query, so that you don't need to continually refer to the schema documentation in the GraphQL Explorer to know which fields are queryable.

Query Complexity Limit

In order to provide a more responsive and efficient experience when using the Storefront GraphQL API, we employ a query complexity calculation mechanism. This mechanism ensures that only queries that fall within a predefined complexity threshold are allowed to be executed.

If your query complexity exceeds the established limit, you will receive a message that provides information about both your query's complexity cost and the predefined threshold.

This message serves as a notification to help you understand why your query was not executed as expected:

{
  message: "The query complexity 1,280,000 exceeds the limit of 640,000.",
  extensions: {
    "requestedQueryCost": 1280000,
    "code": "COMPLEXITY_ERROR"
  }
}

How to optimize queries

Understanding how to optimize your GraphQL queries is essential for achieving efficient and responsive API interactions. While we handle the intricacies of complexity calculation on our end, you can follow some best practices to ensure your queries perform optimally:

Minimize unnecessary nesting for fields

Avoid excessive nesting of fields within your queries. Simplify your query structure by reducing nesting levels, which can significantly improve the speed of query execution.

Request only the data you truly need

Simplify your query structure further by requesting only the data you genuinely require. This practice applies not only to nesting fields but also to attributes. By minimizing unnecessary data retrieval, you can enhance query efficiency and reduce computational overhead.

Use first argument wisely

When using fields that accept a first argument, consider the number of items you genuinely require. Providing an appropriate value for first can help reduce the computational load on the server.

If you do not provide a first filter in your query, the default value of 100 will be used.