The three ways to use the Content Delivery API (GraphQL)

there are three ways to get content from the Public Content API (Photo by Nathan Dumlao on Unsplash (pnmRtTHWqDM)

This post describes the main three ways to get content from the Dynamic Experience Delivery Content API in the context of Tridion Sites and concludes with some tips for managing hyperlinks across content. Spoiler alert: it's not by manual links.

You can get content from the GraphQL-based Content Delivery API using:

  • rawContent, as a way to continue to use the Component Presentations concept but in your Content Delivery-side application
  • unTyped, as the way to get the "templateless" JSON from the data pipeline, where your view or rendering or logic occurs in your application and/or ultimately in a browser
  • Semantic content models, manually (or automatically as of Tridion Sites 9.6), as the latest-and-greatest way to work with more domain-specific objects in your application

Before we get to the details, let's mention some terminology:

  • Tridion Sites is the enterprise web content management system this post mostly covers
  • Tridion Docs is the component content management system that forms the other part of the Tridion product suite
  • Dynamic Experience Delivery (DXD) is the content delivery system for both Tridion Sites and Tridion Docs
  • The Public Content API (PCA) is the GraphQL-based API and endpoint to retrieve content from DXD that has been published from Tridion Sites or Tridion Docs

This post will focus on Tridion Sites, though there is some overlap with Tridion Docs in terms of DXD and the queries. 

Keep in mind the API is named the Public Content API (PCA). You might hear it referred to as "GraphQL," but remember that GraphQL refers to the standard and format of the requests and responses, rather than the API itself.

Read on for examples and more context on when to use rawContent, unTyped content, or semantic content models with the PCA. 

rawContent

Get me Content Manager-rendered content.

You can use the rawContent property especially for legacy setups that rely on Content Manager (CM) templates that publish some text-based output such as JSON, XML, or (X)HTML. The rawContent property has the Component Presentation or CM-side rendered output of Components run against Component Templates.

Here are some examples from a post by :

He has an example for getting page content:

{
  page(namespaceId:1, publicationId:5, pageId:321) {
    itemId,
    publicationId,
    url,
    rawContent {
     data
     }
    }
}

And another for getting a Component Presentation: 

{
  componentPresentation(namespaceId: 1, publicationId: 5, componentId: 123, templateId: 2) {
    component {
        title
        itemId
        creationDate
        }
    }
}

Astute readers might notice that in GraphQL commas are optional in the request, but you might prefer them for legibility.

See more examples and read the documentation on RWS Documentation Center, which has these examples.

{
  page (pageId: 275292, publicationId: 2287238, namespaceId: 1) {
    fileName
    rawContent(renderContent: true) {
      content
    }   
  }
  componentPresentation (namespaceId: 1, publicationId: 19, componentId: 32, templateId: 17) {
    title
    rawContent(renderContent: true) {
      content
    }
  }
}

If you quickly glanced at these examples but know Tridion Sites, what does a publicationId of 2287238 likely mean? Thinking

But why is it called "raw?" and when would you use it?

It might be easy to expect "rawContent" to provide, well, raw untouched data. But it's really "raw" from the perspective of Content Delivery. Technically, this content is "baked," to use an older CMS analogy, as in rendered in the Content Manager and then served to delivery.

Tridion Stack Exchange user Dhara encountered this question when trying to use rawContent in this question and not getting any data (excellent question, btw).

So if your CMS users continue to select templates or you have a very specific format in XHTML, HTML, XML, or JSON that you want rendered from the CMS itself, you would use rawContent in your PCA queries.

For example, one use case might be to process the entire structure of pages on the Content Manager side into some XML or JSON format. Rather than trying to construct, say, a sitemap structure on the delivery side, you might still use Content Manager logic to manage navigational structure. Here it could make sense to get the raw content.

Or you might be familiar with a few JSON-based Content Delivery-side models such as the format from Dynamic Delivery 4 Tridion (DD4T) or the Digital Experience Accelerator (DXA) R2 model. If you wanted to start using the Public Content API while reusing DD4T or DXA R2 models, you could choose to use the rawContent property under a componentPresentation query.

However, if creating a new experience without legacy CM templates, you might "just want the data" as it comes from the Content Management System (CMS).

Note: in general you'll want to use renderContent set to true because this will resolve Tridion Content Delivery Link (TCDL) content tags to URLs. So rather than getting a <tcdl:ComponentLink/> tag, you'll instead get the link resolved to the closest page the component appears on. Setting this false might be useful for troubleshooting, but in practice you want Content Delivery to resolve these. And again, this is mainly if you're still using Component Presentations and not yet using the out-of-the-box, templateless data pipeline JSON or semantic content models.

unTyped 

Get me just the (untyped) content data.

If you're looking for just the data as it comes from the CMS through the Data Pipeline (also known as "templateless publishing"), then you can choose to use an inline query to get "unTypedContent."

In this example, the query gets details from a given Page, with inline queries for Components and (untyped) content.

{
pagequery: page(namespaceId: 1, publicationId: 7, pageId: 726) {
    itemId
    title
    url
    regions {
      name
      components {
        title
        ... on Component {
          itemId
          title
          content {
            ... on UntypedContent {
              data
            }
          }
        }
      }
    }
  }
}

This is a good approach when you're just starting to work with the PCA and you want to get the JSON for Components or the region and structure data from pages. You control the experience and look-and-feel from your application and you just want to get and pass content as data to your front-end applications or clients.

The main caveat with using "unTyped" queries is that Pages and Components are retrieved separately. After getting a Page back, you'll need separate queries to request the Components on the Page.

However, there is a way to get more explicit content models in fewer requests by using Semantic Content Models in Content Delivery.

Semantic Content Model

Get me the (typed) content, matching the model (Schema) in the CMS.

As of Tridion Sites 9.5, the Content Manager and Content Delivery introduced the idea of semantic content models where rather than delivering raw (CM rendered) Component Presentations or untyped JSON, you could configure Content Delivery to deliver content mapped to its definition in the CMS. This mapping is done automatically as of Tridion Sites 9.6.

For example, rather than getting back a Tridion Sites Component, over the PCA you could get back an article, banner, or any other content type based on the Tridion Sites Schema.

This semantic content model can be configured in Content Delivery and it gives you the ability to get a given item's data according to its CMS Schema definition.

Though this mapping is flexible enough to completely change the Schema names and fields between the CM and CD (especially with Tridion Sites 9.5), in practice it's good a good idea to align, or at least start, with the Schema definitions for consistency and to simplify development, troubleshooting, and maintenance.

The main gotcha with getting back these typed, semantic content models is that for a given Page Template from the CMS, you'll need to account for all the possible Content Types for that Page Template's regions.

This can work when you have a clear content model defined in terms of Page Templates, Schemas, and Regions.

See the following example from  in his Tridion Stack Exchange answer to my earlier questions about the PCA.

{
  page(namespaceId: 1, publicationId: 14, url: "/finance_articles.html") {
    publicationIditemIdtitleregions{
      namecomponents{
        itemIdtitle... on FinanceArticle {
          headingsubHeadingbodyText {
            html }
          numberFielddateFieldimage {
            ... on Image {
              titlemetadata {
                altText }
              variants {
                edges {
                  node {
                    urldownloadUrl}
                }
              }
            }
          }
          metadata{
            metadataField1financeArticleType{
              ... on Keyword{
                titledescriptionkey}
            }
          }
        }
      }
    }
  }
}

However, you may not necessarily want to make changes to your PCA queries as your content types (Schemas) and page types change.  Historically, with CMS templating this was an exercise you always had to do in the CMS. Anytime you added a new type of content, you needed to define how it would present with a Component Template as well as any interactions it had with a page in terms of placement and possibly look-and-feel or styles. The difference now is the ultimate act of rendering the content is often done client-side or in the target given application that consumes content from the PCA, rather than by the CMS.

If you agree, consider voting for this idea for the ability to get all the Semantic Content Models automatically in a single Page query. Speaking with Product Management and Development, this is definitely a familiar request and I wouldn't be surprised to see changes in a future version of DXD. 

Hyperlinks

Managing hyperlinks without links. How do you get back a URL?

One concept that's quite elegantly solved with a content management system is handling links to items. 

Rather than relying on manual (unmanaged) hyperlinks, Tridion Sites, dynamically delivers hyperlinks through references to Components. This is especially useful since content and pages are managed separately. And for many "read more about…" scenarios, you don't even need to have editors add links themselves.

For the very common use case of showing summaries and full versions of some content, editors just need to add the same Component to the "summary" and "detail" pages.

Your application can then create the link automatically using the Component Link query. You do so by passing the current page ID, the Component ID, and some additional parameters to the PCA.

See the component and page link queries to get items by url:

{
  componentLink(namespaceId: 1, publicationId: 11, sourcePageId: 92, targetComponentId: 757, excludeComponentTemplateId: 4521) {
    url
    itemId
    type
    }
}

Assuming the target Component is published on (a different) page this query returns the resolved URL to the closest page the Component appears on. Read more on how Content Delivery resolves links to the closest page.

Note that in future versions of the PCA, an explicit resolvedLink attribute is being added so a separate query isn't needed to get the URL for a given Component. 

In summary, consider using rawContent for legacy purposes, troubleshooting, or to otherwise retrieve CM-rendered content. For new projects, use untypedContent or better yet, Semantic Content Model queries. Avoid having editors manually enter links where possible by using the component link queries (or the resolved URL property in the future).

Happy coding!

Edit (2023-10-24): fixed a typo in the code samples (they were missing a space after "on").

Also, a publicationId of 2287238 is either a contrived example or from a test machine with millions of publications.