
What is GraphQL?
The most popular image to describe GraphQL is propably the burger image. Normaly the image shows a smaller burger for GraphQL, because GraphQL is best used to request exactly what you need and nothing more. But we are hungry, so we request a tripple burger - because we have the freedom to do it.
And that's the beauty about GraphQL compared to REST API: We are no longer sole depending on what the API gives us - we can create our own API (of course with limitations). So let's see how GraphQL can be used in AEM and what advantages it has over Assets API or the normal Sling Model Exporter way with components.
In AEM, GraphQL is only working with Content Fragments at the moment, which have a structure defined by the Content Fragment Models.
Quick Setup in AEM
Let's start with the basic setup to see how simple the configuration is.
Prerequisite
- You need AEM as a Cloud Service or at least AEM Version 6.5.10 or higher
- A project under Tools > General > Configuration Browser is created (in our case it's called "my-project")
- A Content Fragment Model and a Content Fragment is avialable under this project
1) Define a GraphQL endpoint under Tools > Assets > GraphQL




Create your first GraphQL Query
For testing purposes, we send our first request to the AEM author. You need to send a post request with authentication header to the endpoint address on author instance. For example "/content/_cq_graphql/my-project/endpoint.json" for endpoint "my-project"
The body of the request contains the query. For example a query to request a single article with headline and text.
{
articleByPath(_path: "/content/dam/my-project/articles/our-test-article") {
item {
headline
content {
plaintext
}
}
}
}
The result will look like this
{
"data": {
"articleByPath": {
"item": {
"headline": "Our Test Article",
"content": {
"plaintext": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum."
}
}
}
}
}
Now if we want to request also the images of the article we send this request
{
articleByPath(_path: "/content/dam/my-project/articles/our-test-article") {
item {
headline
content {
plaintext
}
images {
... on ImageRef{
type
_path
_authorUrl
_publishUrl
width
height
mimeType
}
}
}
}
}
And get this result
{
"data": {
"articleByPath": {
"item": {
"headline": "Test Headline",
"content": {
"plaintext": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum."
},
"images": [
{
"type": "image",
"_path": "/content/dam/my-project/articles/our-test-article/image1.jpg",
"_authorUrl": "http://localhost:4502/content/dam/my-project/articles/our-test-article/image1.jpg",
"_publishUrl": "http://localhost:4503/content/dam/my-project/articles/our-test-article/image1.jpg",
"width": 1284,
"height": 1605,
"mimeType": "image/jpeg"
},
{
"type": "image",
"_path": "/content/dam/my-project/articles/our-test-article/image2.jpg",
"_authorUrl": "http://localhost:4502/content/dam/my-project/articles/our-test-article/image2.jpg",
"_publishUrl": "http://localhost:4503/content/dam/my-project/articles/our-test-article/image2.jpg",
"width": 1284,
"height": 1605,
"mimeType": "image/jpeg"
}
]
}
}
}
}
Security and caching with Persistent Queries
We now have explored how we can send a POST request with a GraphQL query to AEM author, but how can we secure this query to not give more information to the public than allowed and also cache the result?
To achieve this we need to use the so called Persistent Queries.
After preparing a query with a POST request, it can be persistet, so it can be requested with a GET request that can be cached by HTTP caches or a Content Delivery Network (CDN). This is required, as POST queries are usually not cached, and giving out all the schema information public is not recommended.
Create Persistent Queries
1) Enable "GraphQL Persistent Queries" for your project/configuration under General > Configuration Browser > "my-project" > Properties

2) Persist the query by sending a PUT request to the desired endpoint with this URL
- /graphql/persist.json/my-project/get-simple-article
("get-simple-article" can be any name for your query)
Example Query with a parameter
query GetSimpleArticleByPath($apath: String!) {
articleByPath(_path: $apath) {
item {
headline
content {
plaintext
}
}
}
}
To update the query send a POST request. More on that can be found in the Adobe documentation
Now the query is stored under /conf/my-project and can also be included in a package or backup.

The query can now be requested via GET request and the result will be cached depending on the dispatcher settings.
Use this URL for the GET request
- /graphql/execute.json/my-project/get-simple-article;apath=%2Fcontent%2Fdam%2Fmy-project%2Ftest-article
Don't forget to replicate the query under /conf/my-project/settings/graphql/persistentQueries to make the persistent query available on the publish instance.
When to use GraphQL
We now have a basic understanding what GraphQL looks like and how it can be used in AEM. But as with all technologies it needs the right use case.
GraphQL offers many possiblities, and especially with Apps or Single Page Applications (SPA) it can bring the flexibility that most developers wish for.
Some other scenarios are
- Dynamic web components
- Rapid Prototyping
- Multiple output channels with different frontend technologies
- Content Management Purposes in combination with Assets HTTP API
Example for SPA with GraphQL in AEM
https://github.com/adobe/aem-guides-wknd-graphql
Limitations
In the backend, AEM translates the GraphQL queries to SQL2 queries. In case we have complex GraphQL queries, we are fully depending on AEM to produce performant SQL2 queries for us. This can lead to slow performance, if not looked at carefully.
GraphQL in AEM is quite new and it brings a lot of new possibilites, especially for fast prototyping. For big data structures it can reach limitations in regards of how data can be requested.
The Alternatives for Headless Content in AEM
Assets HTTP API
The Assets API of AEM is a well established and quite powerfull API to request Content Fragments and other Assets as JSON Data. But the strong side of Assets API is the possibility to add, edit and delete data. When requesting data it is restricted to simple listing of folder contents or when requesting Content Fragments only the whole Content Fragment can requested and not parts of it.
In short, use Assets HTTP API if
- You are fine getting all data, even data that you don't need
- Caching is no big topic for you
- You need an API to store, update, delete data and not only request it
Sling Model Exporter (Components/Experience Fragments)
This is the "normal" AEM way. You create pages on the pages components and then write your Sling Model Exporter java code to export the data that you need. You can also use the Adobe Core Components and include Content Fragments into your pages quite simple.
In short, use Sling Model Exporter if you
- are fine with using "export pages" that need to be created and published separatly from the Content Fragments to update cache etc.
- want to write and deploy code for custom/special requests
What the future holds
Adobe is pushing AEM with GraphQL and in the documentation we can read
“The AEM GraphQL API offers total control on the JSON output, and is an industry standard for querying content.
Moving forward, AEM is planning to invest in the AEM GraphQL API.”
This is a very good sign and we are excited what the future will bring for AEM Headless with GraphQL.
Further information
More information on GraphQL with AEM
AEM GraphQL API for use with Content Fragments
Example Queries