Best Practices: Content Fragment Models and GraphQL Queries for AEM Headless Implementation


Unlocking the potential of headless content delivery in Adobe Experience Manager (AEM) is a journey that begins with a solid foundation in Content Fragment Models (CFM) and GraphQL queries. In this blog, we’ll embark on this journey and explore the best practices and guidelines for designing CFMs and crafting GraphQL queries that empower your AEM headless implementation.

Guildelines for Content Fragment Models.

  • Use Organism, Molecule, and Atom (OMA) model for structuring Content Fragment Models. It provides a systematic way to organize and model content for greater flexibility and reusability.
    • Organism: Organisms represent high-level content entities or content types. Each Organism corresponds to a specific type of content in your system, such as articles, products, or landing pages. Organisms have their own Content Fragment Models, defining the structure and properties of that content type. Example:
      • Organism: “Article”
      • Content Fragment Model: “Article Content Fragment Model”
    • Molecule: Molecules are reusable content components that make up Organisms. They represent smaller, self-contained pieces of content that are combined to create Organisms. Molecules have their own Content Fragment Models to define their structure. Example:
      • Molecule: “Author Block” (includes author name, bio, and profile picture)
      • Content Fragment Model: “Author Block Content Fragment Model”
    • Atom: Atoms are the smallest content elements or data types. They represent individual pieces of content that are used within Molecules and Organisms. Example:
      • Atom: “Text” (represents a single text field) in CFM
  • Relationships: Identify relationships between CFMs that reflect the relationships between different types of content on your pages. Also, GraphQL’s strength lies in its ability to navigate relationships efficiently. Ensure that your CFMs and GraphQL schema capture these relationships accurately. Use GraphQL’s nested queries to request related data when needed. For example, an “Author” CFM might have a relationship with an “Article” CFM to indicate authorship.
  • Page Components Correspondence: Identify the components or sections within your web pages. Each of these components should have a corresponding CFM. For example, if your pages consist of article content, author details, and related articles, create CFMs for “Article”, “Author” and “Related Articles” to match these page components.
  • Hierarchy and Nesting: Consider the hierarchy of content within pages. Some pages may have nested content structures, such as sections within articles or tabs within product descriptions. Create CFMs that allow for nesting of content fragments, ensuring you can represent these hierarchies accurately.
  • Manage the number of content fragment models effectively: When numerous content fragments share the same model, GraphQL list queries can become resource-intensive. This is because all fragments linked to a shared model are loaded into memory, consuming time and memory resources. Filtering can only be applied after loading the complete result set into memory, which may lead to performance issues, even with small result sets. The key is to control the number of content fragment models to minimize resource consumption and enhance query performance.
  • Multifield in Content Fragment Models: Adobe’s out-of-the-box (OOTB) offerings include multifields for fundamental data types such as text, content reference, and fragment reference. However, in cases where more intricate composite multifields are required, each set should be established as an individual content fragment. Subsequently, these content fragments can be associated with a parent fragment. GraphQL queries can then retrieve data from these nested content fragments. For an example, refer to link
  • Content hierarchy for GraphQL optimization: Establishing a path-based configuration for content fragments is essential to enhance the performance of GraphQL queries. This approach enables queries to efficiently navigate through folder and content fragment hierarchies, thereby retrieving information from smaller data sets.
  • Dedicated tenant/config folders: In the scenario of large organizations encompassing multiple business units, each with its unique content fragment models, it’s advisable to strategize the creation of content fragment models within dedicated /conf folders. These /conf folders can subsequently be customized for specific /content/dam folders. The “Allowed Content Fragment Models” property can be leveraged to restrict the usage of specific types of CFMs within a folder.
  • Field Naming: Opt for transparent and uniform field names across both CFMs and GraphQL types. Select names that provide a clear indication of the field’s function, simplifying comprehension for both developers and content authors when navigating the content structure.
  • Comments: Incorporate detailed descriptions for every field found in CFMs and GraphQL types. These comments should offer valuable context and elucidate the purpose of each field, aiding developers and content authors in comprehending how each property is intended to be utilized and its significance in the overall structure.
  • Documentation: Ensure the presence of thorough documentation for both CFMs and GraphQL schemas. This documentation should encompass the field’s purpose, the expected values it should contain, and instructions on its utilization. Additionally, provide clear guidelines regarding the appropriate circumstances and methods for using specific fields to maintain uniformity. Any data relationships or dependencies between fields should also be documented to offer guidance to developers and content authors.
  • Contemplate the option of integrating CFMs into your codebase, limiting editing access to specific administrators if necessary. This precautionary measure helps mitigate the risk of unintended modifications by unauthorized users, safeguarding your content structure from inadvertent alterations.
  • In the context of AEM Sites, it is advisable to prioritize the utilization of QueryBuilder and the Content Fragment API for rendering results. This approach enables your Sling models to effectively process and transform the raw content for the user interface.
  • Consider employing Experience Fragments for content that marketers frequently edit, as they provide the convenience of a WYSIWYG (What You See Is What You Get) editor.

Guildelines for graphQL queries

Sharing the general guidelines around creating graphQL queries. For syntax based suggestions, please refer to the links in References section.

  • Query Complexity: Consider the complexity of GraphQL queries that content authors and developers will need to create. Ensure that the schema allows for efficient querying of content while avoiding overly complex queries that could impact performance.
  • Pagination Implement offset/cursor-based pagination mechanisms within your GraphQL schema. This ensures that queries return manageable amounts of data. It’s advisable to opt for cursor-based pagination when dealing with extensive datasets for pagination, as it prevents premature processing.
// Offset based pagination
query {
   articleList(offset: 5, limit: 5) {
    items {
      authorFragment {
        lastName
        firstName
      }
    }
  }
}

//cursor-based pagination
query {
    adventurePaginated(first: 5, after: "ODg1MmMyMmEtZTAzMy00MTNjLThiMzMtZGQyMzY5ZTNjN2M1") {
        edges {
          cursor
          node {
            title
          }
        }
        pageInfo {
          endCursor
          hasNextPage
        }
    }
}

  • Security and Access Control: Implement security measures to control who can access which content from GraphQL queries. Ensure that sensitive data is protected and that only authorized users can execute certain queries or mutations. Here is an example on how to use CUG with GraphQL queries
  • Query only the data you need, where you need it: In GraphQL, clients can specify exactly which fields of a particular type they want to retrieve, eliminating over-fetching and under-fetching of data. This approach optimizes performance, reduces server load, enhances security, and ensures efficient data retrieval, making GraphQL a powerful choice for modern application development.
  • Consider utilizing persisted queries as they offer optimization for network communication and query execution. Rather than transmitting the entire query text in every request, you can send a unique persisted-label that corresponds to a pre-stored query on the server. This approach takes advantage of server-side caching, allowing you to make GET requests using the persisted-label of the query, which enhances performance and reduces data transfer.
  • Sort on top level fields: Sorting can be optimized when it involves top-level fields exclusively. When sorting criteria include fields located within nested fragments, it necessitates loading all fragments associated with the top-level model into memory, which negatively impacts performance. It’s important to note that even sorting on top-level fields may have a minor impact on performance. To optimize GraphQL queries, use the AND operator to combine filter expressions on top-level and nested fragment fields.
  • Hybrid filtering: Explore the option of implementing hybrid filtering in GraphQL, which combines JCR filtering with AEM filtering. Hybrid filtering initially applies a JCR filter as a query constraint before the result set is loaded into memory for AEM filtering. This approach helps minimize the size of the result set loaded into memory, as the JCR filter efficiently eliminates unnecessary results beforehand. JCR filter has few limitations, where it does not work today, like case-insensitivity, null-check, contains not etc
  • Use dynamic filters: Dynamic filters in GraphQL offer flexibility and performance benefits compared to variables. They allow you to construct and apply filters dynamically during runtime, tailoring queries to specific conditions without the need to define multiple query variations with variables. More details in video (time 6:29)
//Query with Variables
query getArticleBySlug($slug: String!) {
  articleList(
    filter: {slug: {_expressions: [{value: $slug}]}}
   ) {
    items {
      _path
      title
      slug
    }
  }
}

//Query-Variables
{"slug": "alaskan-adventures"}
//Query with Dynamic Filter
query getArticleBySlug($filter: 
  ArticleModelFilter!){  
    articleList(filter: $filter) {
    items {
      _path
      title
      slug
    }
  }
}

//Query-variables
{
  "filter": {
    "slug": {
      "_expressions": [{"value": "alaskan-adventures"}]
    }
  }
}

For more info on how to optimize GraphQL queries:

2 thoughts on “Best Practices: Content Fragment Models and GraphQL Queries for AEM Headless Implementation

Leave a comment