The GraphQL content schema

Version: 22.x

Sitecore GraphQL has a standard schema provider that you use to query Sitecore content items. This provider has strongly typed template access, field type metadata support, and other features that make it an ideal access layer for most Sitecore front-end projects that need content data.

Strongly typed items

GraphQL supports types and interfaces, and you use them by injecting the template definition into the schema. You can get template fields in a strongly-typed way by using inline fragments that select fields from specific types. The following is an example of getting the default home item’s fields this way:

RequestResponse
{
  item(path: "/sitecore/content/home") {
    id
    ...on SampleItem {
      text {
        editable
      }
      title {
        editable
      }
    }
  }
}

This query returns something similar to the following:

RequestResponse
{
  "data": {
    "item": {
      "id": "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}",
      "text": {
        "editable": "<p style=\"line-height: 22px;\">From a single connected platform that also integrates with other customer-facing platforms, to a single view of the customer in a big data marketing repository, to completely eliminating much of the complexity that has previously held marketers back, the latest version of Sitecore makes customer experience highly achievable. Learn how the latest version of Sitecore gives marketers the complete data, integrated tools, and automation capabilities to engage customers throughout an iterative lifecycle &ndash; the technology foundation absolutely necessary to win customers for life.</p>\n<p>For further information, please go to the <a rel=\"noopener noreferrer\" href=\"https://doc.sitecore.net/\" target=\"_blank\" title=\"Sitecore Documentation site\">Sitecore Documentation site</a></p>"
      },
      "title": {
        "editable": "Sitecore Experience Platform"
      }
    }
  }
}

The GraphQL type system supports template inheritance. The following example shows how to get the items that the Insert Options of an item point to:

RequestResponse
{
  item(path: "/sitecore/content/home") {
    # Treat the home item as the system 'Insert Options' template type, and this works
    ...on InsertOptions {
      masters {
        targetItems {
          displayName
          uri
        }
      }
    }
  }
}

Typed field access

Sitecore GraphQL supports typed access to field values, such as link fields and multi-lists.

The following is an example of querying an item by path, run on an extended Sample Item template:

RequestResponse
{
  item(path: "/sitecore/content/home") {
    __typename
    # Sample multilist and link (additional fields also available)
    ...on SampleItem {
      myMultilist {
        targetItems {
          id
          path
          ...on Home {
            navigationTitle {
              editable
            }
          }
        }
      }
      myLinkField {
        url
        text
        editable
      }
    }
    
    # Typing in named-field API
    myLinkFieldByName: field(name: "My Link Field") {
      name
      editable
        ...on LinkField {
        url
        text
      }
    }
  }
}

For the query defined in the previous example, Sitecore GraphQL returns a data structure similar to:

RequestResponse
{
 
"data": {
    "item": {
     
"__typename": "SampleItem",
     
"myMultilist": {
       
"targetItems": [
          {
           
"id": "{C7C95984-E060-42D9-BBC6-B45C18768905}",
           
"path": "/sitecore/content/Habitat/Settings"
          },
          {
            "id":
"{DAC24EDD-44FB-42EF-9ECD-1E8DAF706386}",
           
"path": "/sitecore/content/Habitat/Home",
           
"navigationTitle": {
             
"editable": "Navigation Title"
            }
          }
        ]
      },
     
"myLinkField": {
       
"url": "https://sitecore.net",
       
"text": "Awesome Link",
       
"editable": "<a
href=\"https://sitecore.net\">Awesome Link</a>"
      },
     
"myLinkFieldByName": {
       
"name": "My Link Field",
       
"editable": "<a href=\"https://sitecore.net\">Awesome
Link</a>",
       
"url": "https://sitecore.net",
       
"text": "Awesome Link"
      }
    }
  }
}

Template access

You can use an API to access Sitecore Templates, for example:

RequestResponse
{
  templates(path: "/sitecore/templates/sample/Sample Item") {
    name
    baseTemplates {
      name
    }
    ownFields {
      name
      id
      unversioned
      shared
    }
  }
}

Because of the GraphQL type system, the type returned by the ownFields is an array of the same type returned by definition on an item field - with the same implementation. This makes it easy to expose rich APIs, for example, if you want to expose the results of special items filtering. You then return ItemInterfaceGraphType from your GraphQL field and pass it your Item as a source. The full power of querying the ItemInterfaceGraphType is available to your consumer, including getting template field definitions.

Content search API

There is a basic Content Search API designed to fulfill the needs of keyword searching, mostly because search queries can quickly grow in complexity beyond what a generic API can provide. The following is an example of using this API:

RequestResponse
{
  search(keyword: "sample" first: 3 facetOn: ["_template"]) {
    results {
      # Result info using the Connection pagination pattern
      # (the standard way to do paging in GraphQL)
      totalCount
      pageInfo {
        hasNextPage
        hasPreviousPage
      }
      items {
        # these values are from the index
        score
        path
        # but this resolves the actual item - and because it's an Item type
        # we can do anything we can do to an item - type it, query it
        # anything. It's lazy, so unless we query the item property, the item
        # is not looked up.
        item {
          icon
          ...on Template { 
            masters {
              displayName
            }
          }
        }
      }
    }
    # and we can do faceting, too
    facets {
      name
      values(hideEmpty: true) {
        count
        # just like the search results, for facets that are IDs,
        # we can choose to resolve their Item from the database
        # and query it with full capabilities
        item {
          displayName
          icon
        }
      }
    }
  }
}

The result is similar to the following:

RequestResponse
{
  "data": {
    "search": {
      "results": {
        "totalCount": 12,
        "pageInfo": {
          "hasNextPage": true,
          "hasPreviousPage": false
        },
        "items": [
          {
            "score": 2.16668963432312,
            "path": "/sitecore/system/settings/rules/insert options/rules/analytics campaigns",
            "item": {
              "icon": "http://habitat.dev.local/-/icon/Software/32x32/shape_ellipse.png"
            }
          },
          ...
        ]
      },
      "facets": [
        {
          "name": "_template",
          "values": [
            {
              "count": 3,
              "item": {
                "displayName": "Sublayout",
                "icon": "http://habitat.dev.local/-/icon/Software/16x16/element_selection.png"
              }
            },
            {
              "count": 2,
              "item": {
                "displayName": "Folder",
                "icon": "http://habitat.dev.local/-/icon/Applications/16x16/folder.png"
              }
            },
            ...
          ]
        }
      ]
    }
  }
}

Subscriptions

Subscriptions are a simple abstraction over real-time data updates. This is similar to how SignalR operates, except subscriptions are limited to specific types of GraphQL queries. You make the query, but you do not get any results immediately. The query remains open until you tell it to stop, and the query can return multiple real-time results. An example use case is the itemSaved subscription:

RequestResponse
subscription {
  itemSaved {
    item {
      id
      ...on SampleItem {
        title {
          rendered
        }
      }
    }
    changes {
      fieldChanges {
        fieldName
        newValue
      }
    }
  }
}

After this subscription is started, you get a new query result every time an item is saved in the content endpoint’s database:

RequestResponse
{
  "itemSaved": {
    "item": {
      "id": "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}",
      "title": {
        "rendered": "subscriptions rock"
      }
    },
    "changes": {
      "fieldChanges": [
        {
          "fieldName": "__Updated",
          "newValue": "20171222T153248Z"
        },
        ...
      ]
    }
  }
}

Subscriptions use the WebSocket protocol to enable their real-time nature. They enable real-time elements in your UI. Subscriptions fit well with the Observable pattern from Reactive Extensions on the server and RxJS on the client. You can think of an observable as an asynchronous stream of events or perhaps a JavaScript Promise that can resolve multiple times.

Unique names

In Sitecore, multiple templates can have the same name (for example, File) and templates with fields whose names conflict with core fields on the item graph type (for example, Icon).

In GraphQL, names of types and fields must be unique. When a naming collision occurs, the item or field item with the newest creation date has _{guid} appended to the name. The creation date is used because the ordering must be stable, so a graph type name is never changed after it has been referenced. If you make a mistake and create a template with the same name as a system template, the system template’s graph type name does not change because it is older.

You can strongly type only a subset of the templates defined in Sitecore to avoid this problem. This is a best practice for customer-created API endpoints, because these only need to serve templates defined in their projects.

Do you have some feedback for us?

If you have suggestions for improving this article,