Getting Started with Headless Tutorial

October 8, 2024

GraphQL APIs in Jahia

This tutorial teaches you how to work with Jahia’s jContent as a headless CMS. A headless CMS is used to create/contribute content which will be consumed by a Single Page Application (SPA), a Progressive Web App (PWA), a native mobile application or any other third party.
In this tutorial, you will learn more about the headless capabilities of jContent. After that, you will create a simple SPA (jquery, react or angular based apps) and see how to interact with jContent to contribute content and consume it from the application.

This tutorial is the first of three tutorials. You will learn how to:

  • Create a new headless project and deploy content definitions in jContent
  • Create or contribute content in jContent
  • Configure jContent to allow content retrieval from our SPA through GraphQL API
  • Create and test GraphQL query using our tool GraphiQL

Before you begin

This tutorial assumes that you have already downloaded and installed Jahia or requested access to an instance on Jahia cloud.

Terms you should know

Here are a few terms you should know about before you get started:

  • Module - packages that can be deployed on a Jahia platform to extend or modify it, similar to a plug-in. Understanding Jahia modules has more detailed information about deploying modules on Jahia.
  • Headless CMS - in a Content Management System (CMS), Headless means that the content is created without display or usage context. Thus, the content is ready to be consumed as it is by a SPA (Single Page webApp),a native mobile application or any other third party. The Headless approach became popular in conjunction with the growth of native mobile apps and more recently with the development of SPAs. Note : in jContent, headless content can also be used in standard web sites.
  • GraphQL - a query language for APIs and a runtime for fulfilling those queries with your existing data.
  • jQuery - is a free JavaScript library designed to simplify HTML tree traversal and manipulation, as well as event handling, CSS animation, and Ajax.
  • Jackrabbit/Java content repository (JCR) - The JCR is a tree organisation of all the content stored in Jahia. In this tree each content is a node on which the system can apply read/write permission. It is like your file system in your computer but designed for Java.
  • Namespace - A namespace is used as a unique path to be sure the system accesses the right element. The namespace is used by content definition to ensure the content definition name is unique. It is composed by a prefix and an URI that will be written in the header of the definition file. Note : a namespace can be compared to a “postal address” where prefix is the street number, URI the street and city and the right element to find in this address is a person.
  • Workspace - is an optional parameter that specifies where in the JCR the content is stored (EDIT or LIVE).
    In jContent we have two different Trees to store the content, one for the editorial content and another one for the live content. Each tree can be viewed as a Workspace (EDIT or LIVE).
    By default in Jahia, if the workspace parameter is not specified then the default will be EDIT.

 

Create a web project

The first thing you’ll need to do to get started is create a new web project that you’ll use for the rest of the tutorial. After that, you’ll deploy and enable a pre-built module to set up the content definition. Even though headless content is not always rendered on a website, you still must create a web project as a master storage container for your content.

To create a new web project follow these steps:

  1. In your dashboard, click Home in the left menu, from the Dashboard Create New in the main pane.
  2. Click CREATE to build a new web project from scratch.
  3. Set these properties for your new web project:
    • Name: Tutorial
    • Site key: tuto (note: this is mandatory for the pre-built artifacts)
  4. Leave the remaining properties set to their defaults, then click Next.
  5. On this next screen, select the following template set:
    • Template set: Jahia Base Demo
  6. Leave the remaining properties set to their defaults, then click Next
  7. Finally click SAVE

To have more detail about web project creation visit the Jahia academy.

Deploying a module

Now you have your project created, you want to create new content. To create your own content, first you need to inform jContent what type of content you want to contribute in terms of content name and content properties.

For example, in our context, you want to create a new content called Tutorial Item. A Tutorial Item has three properties : a title, a body and an image.

All of this information is written in a Content Node Definition (.cnd) file. This file is stored inside a jahia module and can be deployed as needed to enhance jContent capabilities.

 

For this tutorial we have built such a model for you. Thus, you’ll be using a prebuilt module to deploy a new content node definition to your Jahia instance. After you download the module, you’ll learn how to deploy and enable it in jContent.

Downloading and deploying the prebuilt module

The prebuilt module for this tutorial is available on the Jahia Store and is named “Headless tutorial content definitions”.

Jahia allows you to download and deploy modules directly from the administration interface. Please follow the steps in Deploying your module to download and deploy the “Headless tutorial content definitions”

Note that you can find the source code of the Jahia headless tutorial module on GitHub.

Enabling the module

The module is deployed on your platform but you now need to enable it on your newly created website. This feature allows you to only enable the module on the project where you need it.

Please follow the steps in this tutorial to enable your “Headless tutorial content definitions” for your “tuto” website.

Manage content

Module description

As explained previously, the module “headless tutorial content definitions” deployed a new content node definition to our Jahia instance. That content node definition is defined in the definitions.cnd file of the module on Github.

definitions.cnd

<jmix = 'http://www.jahia.org/jahia/mix/1.0'>
<jnt = 'http://www.jahia.org/jahia/nt/1.0'>
<jntuto = 'http://www.jahia.org/jahia/tutorial/nt/1.0'>
<mix = 'http://www.jcp.org/jcr/mix/1.0'>

[jntuto:tutorialItem] > jnt:content, jmix:editorialContent, jmix:structuredContent, mix:title
- jcr:title (string)
- body (string, richtext)
- image (weakreference, picker[type='image']) mandatory

File description:

The content type definition defines a new content type named “tutorialItem” belonging to the namespace “jntuto”.

This content inherits from “jnt:content”, “jmix:editorialContent”, “jmix:structuredContent” and “mix:title”. Those inheritance are here to enrich our newly created content type and make it already available to play with in jContent.

This content type has 3 properties:

  • jcr:title which is a string property defining our content title
  • body which is also a string property but enrich with rich text capabilities
  • image which defines a reference to an image uploaded in Jahia. This image is mandatory

 

This completes the setup for the rest of the tutorial. To learn more about the definitions.cnd syntax check out creating a content type on the Jahia Academy.

Creating content with jContent

Now that our new content definition is available for our “tuto” project, we can start creating content.

Following the creating content tutorial, use jContent to create “Tutorial Item” content in the Content Folder of our “tuto” project. In the content picker, the content type “Tutorial Item” is located under the content category “Content:Structured”.

To learn more please read Overview of jContent in the Jahia Academy.

Publish content 

Finally, you will now need to publish the created content in order to expose it to the outside world and make it available for our Single Page Application.

Following  the Publishing content and files tutorial, publish the entire “tuto” project

Configure content retrieval

Please note that for the purpose of these tutorials, the below configuration allows any web client to communicate to your GraphQL API. It is not recommended when working on an enterprise project since it doesn't provide enough security.

The setting up authorization tutorial provides more information about properly configuring authorization.

Cross-Origin Resource Sharing (already configured on Jahia Cloud)

NOTE: For Cloud users, you may skip this section

Cross-Origin Resource Sharing (CORS) is a mechanism that allows restricted resources on a web page to be requested from another domain. In this case, you’ll want to allow your SPA (which is hosted on its own server) to access resources from our jContent headless server.

In order to have this tutorial working for everybody we will allow any server to request the jContent GraphQL API. Thus, you can configure Tomcat to allow any GraphQL calls from anywhere by adding this filter to your tomcat/webapps/ROOT/WEB-INF/web.xml file, after the existing filters:

<filter>
  <filter-name>CorsFilter</filter-name>
  <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
  <init-param>
    <param-name>cors.allowed.origins</param-name>
    <param-value>*</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>CorsFilter</filter-name>
  <url-pattern>/modules/graphql</url-pattern>
</filter-mapping>
Note: you should always make a backup before adding filters to your web.xml file.
Note 2: in production environment we recommend to create a “provider configuration file” (e.g. org.jahia.modules.graphql.provider-tuto.cfg) as explained here.

Retrieve content

GraphQL provides an alternative to the traditional REST / CRUD API model that allows more flexibility in the query, manipulation of the contents retrieved and services called.

Here is some Jahia-specific information about our Java Content Repository and how Jahia uses GraphQL:

 

Java Content Repository (JCR) Jahia stores content in a Java Content Repository (JCR). The JCR is a hierarchical object database tailored to storing, searching, and retrieving content. Much like in an SQL database, you’ll have to perform queries in order to retrieve content from the JCR database. The JCR-SQL2 Query cheat sheet in the Jahia academy has more information about the JCR and how to query content directly.
Jahia DX GraphQL API There is a Jahia-specific GraphQL implementation that allows you to perform queries directly against the JCR. Using GraphQL to perform queries in the Jahia academy has more details about Jahia-specific GraphQL.

Retrieving content with GraphQL syntax

Using GraphiQL with a local Jahia instance

Jahia embeds a GraphiQL interface that is only available for local instances. We recommend using the GraphiQL interface for editing and testing your GraphQL queries and mutations. The embedded GraphiQL interface (for local Jahia installations) can be found at:

http://[yourlocalhost name]/modules/graphql-dxm-provider/tools/graphiql.jsp 

Using GraphiQL with a Jahia Cloud instance

If you are using Jahia Cloud, you won’t be able to access that URL but you have other options to use GraphiQL:

The GraphQL endpoint is : http://[yourHostName]/modules/graphql.

You have to provide a Basic authorization in the HTTP headers. You can use the root user, for example Basic cm9vdDpoZWxsbw==’ where cm9vdDpoZWxsbw== is based 64 encoded for root:hello ([username]:[password]

Retrieving text fields from our previously defined content node

Here is a query to retrieve text fields from a content node:

{
  # executes a JCR query against the 'live' workspace of Jahia
  jcr(workspace: LIVE) {
  # retrieves a node based on its path.
    nodeByPath(path: "/sites/tuto/contents/tutorial-item") {
  # retrieves the property named 'jcr:title' and associates it with the label 'title'
     title: property(name: "jcr:title"){
  # from that property, we retrieve the value
         value
       }
  # retrieves the property named 'body' and associates it with the label 'body'
      body: property(name: "body"){
  # from that property, we retrieve the value
        value
      }
    }
  }
}

Result:

{
  "data": {
    "jcr": {
      "nodeByPath": {
        "title": {
          "value": "Your title field"
        },
        "body": {
          "value": "<p>Your body content here!</p>\n"
        }
      }
    }
  }
}

How to handle an image reference

{
  jcr(workspace: LIVE) {
    nodeByPath(path: "/sites/tuto/contents/") {
# retrieves the descendants of that node but only the ones of type 'jnt:tutorialItem' 
    descendants(typesFilter: {types: ["jntuto:tutorialItem"]}) {
# iterates of a list of nodes
        nodes {
          title: property(name: "jcr:title") {
            value
          }
          body: property(name: "body") {
            value
          }
          image: property(name: "image") {
            path: refNode {
              path
            }
          }
        }
      }
    }
  }
}

Protecting your API access 

Access to APIs are protected by a security filter in Jahia. This security filter allows you to granularly define API access for each application that will be connected to Jahia. The security filter is configured directly on the filesystem through configuration files.

For each application, you can define:

  • Which content the application has access to
  • How the application can access this content
  • Which security mechanism is protecting this access? (permission, token...)

For the sake of this tutorial, the module “headless tutorial content definitions” already embeds a graphQL API access configuration to your tutorial site:

With Contents:

permission.tuto.api=graphql
permission.tuto.pathPattern=/sites/tuto/contents/.*, /sites/tuto/files/.*
permission.tuto.workspace=live

This file defines an API access named “tuto” which provides a GraphQL access to the live workspace of any content inside the “tuto” sites (under the paths /sites/tuto/contents.* and /sites/tuto/files.*)

Please note that this API access is unprotected, in best practices we would protect this API either with a token and/or a permission. To learn more about security filter and API access please visit:

https://github.com/Jahia/security-filter

Congratulations!  You are ready to build a headless app.  Check out the rest of our tutorials for JavaScript frameworks.

Build an app

Now that you understand the basics of how to build a headless application in Jahia, here are 3 tutorial options for you based on whatever JavaScript framework you are most familiar with.