Advanced headless tutorial

November 14, 2023

Exposing JCR definitions via custom GraphQL entrypoints

In this section you will learn how to map existing JCR types to custom GraphQL API entry points using SDL Generator Tools and use these entrypoints to get data for your application.

  1. How to use the tool
  2. How to get Jahia to recognize the generated SDL schema
  3. How to run queries against custom entry points

This tutorial builds on the work done in the previous tutorial, the same module and components will be used/reused, so make sure to look at that.

We created a demo web application project with ReactJS and Apollo for reference. You can use this repository on the branch graphql-sdl

Mapping a type

Let's see how to map a type.

Add a type

Navigate to http://localhost:8080/tools (your domain and port may differ)and select sdlGeneratorTool from bottom left


Click on Add new type and select the type you want.

Note: by default you will see only the types that are editorial content, but you can use the search bar to search for any type on the system.


If you flip the switch you will be able to access nodes of the given type by path or id if you need to do so.

Note: metadata field is generated by default for all new types. You can remove it if you don't need it.


Add a property

To select a property click on Add property. You will have two options: Select and map property to type and Select property.


If the property is not a complex object type, you should choose Select property. Example below shows selection of title property


You should choose Select and map property to type if the property you want is a weakreference or a child. 


By default there are four predefined types:

  • Asset
  • ImageAsset
  • Category
  • Metadata

Now map industryCat property to Category type.


As list switch allows you indicate if you want the property to be fetched as list or not. It is automatically determined in most cases and should only be manually handled if Select a property field is empty in which the system cannot determine which type you want.

You can add more properties to achieve the following result.

Screen Shot 2019-04-11 at 10.01.46 AM.png

Define finders

Once you have your type and properties setup you can transition to the next step to define a finder. A finder is nothing more than an entry point name.

On Define finder page select the type you want and click on Add a finder and add Company  finder to have allCompany entry point.


In the dialog you will have all available finders based on property selections for a given type.


About finder types

There are three classes of finders: all finders, connection finders and by property finders.

All finders return you everything that's found for that particular type.

Connection finders allow you have pagination and by property finders allow you to select nodes by property, even if the property in question is a weakreference.

Once you have selected the type of finder you want and named it, you are ready to transition to schema export.

Export the schema

On the last step of SDL generation process you have two options: to copy resulting schema to clipboard or to download it as a file. It is up to you which option you decide to choose.

type Company @mapping(node: "jdnt:company") {
    title: String @mapping(property: "jcr:title")
    description: String @mapping(property: "overview")
    image: ImageAsset @mapping(property: "thumbnail")
    industry: Category @mapping(property: "industryCat")

extend type Query {
    allCompany: [Company]

Deploy your schema

Schema deployment is very straight forward. All you need to do is create a module, add graphql-extension.sdl file to META-INF folder and deploy that module. Once the module is deployed any modifications to the schema file will be handled without the need to deploy the module again.

You can check the status of your schema by visiting tools.

Run queries with React/Apollo

In order to use new entry point in the demo web application, there are a few changes that you need to make to ComponentList.container.jsx

Modify the query as follows.

const COMPANIES_QUERY = gql`
    query CompaniesListQuery($language: String) {
        allCompany(language: $language) {
            industry {
            image {

And change the rest of the component as follows

const CompanyListContainer = () => {
    const [selectedIndustry, updateSelectedIndustry] = useState('All');
    const variables = {
        language: "en"
    //By default, there are no companies associated with `Technology` and `Goods` in the demo
    const industries = [
        // 'Technology',
        // 'Goods',
    const generateURL = path => {
        return `http://localhost:8080/${path}?t=thumbnail2`;
    return (
        <Query query={COMPANIES_QUERY} variables={variables} fetchPolicy="network-only">
            {({loading, data}) => {
                let companies = [];
                if (data && data.allCompanies) {
                    //Build the company data as expected by the Company component
                    data.allCompanies.forEach(company => {
                            id: company.uuid,
                            title: company.title,
                            description: company.description,
                            image: generateURL(company.image.url),
                            industry: company.industry.title
                        <Grid container justify="center" spacing={24}>
                            { => {
                               return (
                                   <Grid key={industry} item>
                                       <Typography style={{cursor: "pointer"}}
                                                   color={industry === selectedIndustry ? "textPrimary" : "textSecondary"}
                                                   onClick={() => updateSelectedIndustry(industry)}>
                            <CompanyList loading={loading}
                                         companies={companies.filter(company => selectedIndustry === 'All' || company.industry === selectedIndustry)}

That's it, you are now ready to use your new GraphQL entry point.

In this tutorial, you:

  • Used SDL generator tool to create custom type mapping
  • Created a finder for custom type
  • Exported and deployed SDL schema
  • Modified React app to use new entry point

Where to go from here