Page tree
Skip to end of metadata
Go to start of metadata

Magnolia GraphQL is currently in a private beta phase. It is not yet publically available. The full version is still under development.

This page describes the GraphQL endpoint for obtaining JCR data as JSON. The GraphQL endpoint is a highly flexible Java servlet that processes requests with a defined body.

The GraphQL endpoint is a Magnolia DX Core feature. For an alternative way of data delivery, see the REST Delivery endpoint API v2.

The example GraphQL requests and responses shown below on this page make use of the Bookshelf and Author catalog apps of our demo bookshelf light module (the withAuthorCatalog branch). You can clone the module with this command:

git clone -b withAuthorCatalog --single-branch https://git.magnolia-cms.com/scm/documentation/bookshelf.git

Configuration aspects

Changing endpoint name

All GraphQL requests are by default mapped to /.graphql. You can change this by modifying the pattern property at /server/filters/servlets/GraphQLServlet/mappings/-.graphql--.

Access control

All requests to the GraphQL servlet pass through a filter chain. Make sure that the instance handling GraphQL requests in a production environment has an appropriate assignment of JCR Access Control Lists (ACLs) and Web Access permissions for the GraphQL endpoint and for the JCR workspaces where GraphQL content is stored. For more information, see the Security app.

Handling HTTP methods

The endpoint supports the  POST and GET HTTP methods.

Examples

POST with Content-Type header set to application/graphql:

{
    bookshelves(locale: "en") {
        title
    }
}

POST with Content-Type header set to application/json:

{
   "query":"{ bookshelves ( locale: \"en\" ) { title }}"
}

Response in both cases:

 Click here to see the response ...
{
    "data": {
        "bookshelves": [
            {
                "title": "The War of the Worlds"
            },
            {
                "title": "Contact"
            },
            {
                "title": "On the Origin of Species by Means of Natural Selection, or the Preservation of Favoured Races in the Struggle for Life"
            },
            {
                "title": "A Brief History of Time: From the Big Bang to Black Holes"
            },
            {
                "title": "God Created the Integers: The Mathematical Breakthroughs That Changed History"
            },
            {
                "title": "Brave New World"
            }
        ]
    }
}


GET

http://localhost:8080/.graphql?query=%7Bbookshelves%28locale%3A%20%22en%22%29%20%7Btitle%7D%7D

The endpoint's response is identical to the response obtained through the POST method. The value of the query parameter is a URL-encoded string {bookshelves(locale: "en") {title}}.

For more details how to create a GraphQL-valid header and body, see the HTTP Methods, Headers, and Body of graphql.org. All the examples below utilize the POST method.

Only the GraphQL  query type is supported, the mutation type has not been implemented yet.

Querying content

You can query content of an individual item by providing either its path or its UUID to the path and id arguments, respectively. Content references are resolved automatically. In the following examples, references are resolved for the authors and frontcover fields.

Single item by path

{
    bookshelf(path: "/My-Good-Reads/Science/Darwin-1859-On-the-Origin-of-Species") {
        title
        authors {
            name
        }
        publisher
        publish_date
        frontcover {
            name
            link
        }
    }
}
 Click here to see the response ...
{
    "data": {
        "bookshelf": {
            "title": "On the Origin of Species by Means of Natural Selection, or the Preservation of Favoured Races in the Struggle for Life",
            "authors": [
                {
                    "name": "Charles Darwin"
                }
            ],
            "publisher": "John Murray III",
            "publish_date": "1859-11-24",
            "frontcover": {
                "name": "darwin1859.png",
                "link": "/dam/jcr:da35e99f-6138-40c9-b7c1-57978aa70268/darwin1859.png"
            }
        }
    }
}

Single item by UUID

{
    bookshelf(id: "c2a5ea72-6611-4f70-8005-42e8694fc610") {
        title
        authors {
            name
        }
        publisher
        publish_date
        frontcover {
            name
            link
        }
    }
}
 Click here to see the response ...
{
    "data": {
        "bookshelf": {
            "title": "On the Origin of Species by Means of Natural Selection, or the Preservation of Favoured Races in the Struggle for Life",
            "authors": [
                {
                    "name": "Charles Darwin"
                }
            ],
            "publisher": "John Murray III",
            "publish_date": "1859-11-24",
            "frontcover": {
                "name": "darwin1859.png",
                "link": "/dam/jcr:da35e99f-6138-40c9-b7c1-57978aa70268/darwin1859.png"
            }
        }
    }
}

All items

{
    bookshelves {
        title
    }
}
 Click here to see the response ...
{
    "data": {
        "bookshelves": [
            {
                "title": "The War of the Worlds"
            },
            {
                "title": "Contact"
            },
            {
                "title": "On the Origin of Species by Means of Natural Selection, or the Preservation of Favoured Races in the Struggle for Life"
            },
            {
                "title": "A Brief History of Time: From the Big Bang to Black Holes"
            },
            {
                "title": "God Created the Integers: The Mathematical Breakthroughs That Changed History"
            },
            {
                "title": "Brave New World"
            }
        ]
    }
}

(warning) For all or multiple items, the correct plural form of the queryField must be used in the body. You can verify the form in the Definitions app:

An incorrect plural form is considered as undefined field:

{
    bookshelfs {
        title
    }
}
 Click here to see the response ...
{
    "status": 500,
    "errors": [
        {
            "message": "Validation error of type FieldUndefined: Field 'bookshelfs' in type 'Query' is undefined @ 'bookshelfs'",
            "locations": [
                {
                    "line": 2,
                    "column": 5,
                    "sourceName": null
                }
            ],
            "description": "Field 'bookshelfs' in type 'Query' is undefined",
            "validationErrorType": "FieldUndefined",
            "queryPath": [
                "bookshelfs"
            ],
            "extensions": null,
            "errorType": "ValidationError",
            "path": null
        }
    ]
}

Specific language variant

With the locale argument, you can request a specific language variant. Locale-based content retrieval can be applied to both a single item and multiple items.

{
    bookshelf(
        path: "/My-Good-Reads/Science/Darwin-1859-On-the-Origin-of-Species"
        locale: "de"
    ) {
        title
    }
}
 Click here to see the response ...
{
    "data": {
        "bookshelf": {
            "title": "Über die Entstehung der Arten durch natürliche Zuchtwahl oder die Erhaltung der begünstigten Rassen im Kampfe um’s Dasein"
        }
    }
}

With aliases

GraphQL aliases let you rename the result of a field to anything you want. This functionality is supported by the GraphQL-java library and works out of the box in the Magnolia GraphQL endpoint. In the following example, the originalBookTitle prefix in body species that the title field should be returned as originalBookTitle:

{
    bookshelf(
        path: "/My-Good-Reads/Science/Darwin-1859-On-the-Origin-of-Species"
    ) {
        originalBookTitle: title
    }
}
 Click here to see the response ...
{
    "data": {
        "bookshelf": {
            "originalBookTitle": "On the Origin of Species by Means of Natural Selection, or the Preservation of Favoured Races in the Struggle for Life"
        }
    }
}

Resolving asset references

 To obtain references for assets, you can query either the asset or the assets query field. To resolve references for a single asset, use the asset field and supply the values for the UUID or path properties of that asset. To resolve references for multiple assets, use the assets  field and provide a path or  UUID of a folder.

Note: jcr is the default value for the providerId argument. Unless you need to communicate with a different asset providerproviderId can be omitted, as shown in the second example.

By UUID

{
    asset(providerId: "jcr", id: "da35e99f-6138-40c9-b7c1-57978aa70268") {
        name
        link
        path
    }
}
 Click here to see the response ...
{
    "data": {
        "asset": {
            "name": "darwin1859.png",
            "link": "/dam/jcr:da35e99f-6138-40c9-b7c1-57978aa70268/darwin1859.png",
            "path": "/Book-Covers/darwin1859.png"
        }
    }
}

By path

{
    assets(path: "/Book-Covers") {
        name
        link
    }
}
 Click here to see the response ...
{
    "data": {
        "assets": [
            {
                "name": "wells1898.png",
                "link": "/dam/jcr:d6007e99-c6b1-44f4-ac6e-13c2eefa4379/wells1898.png"
            },
            {
                "name": "huxley1932.png",
                "link": "/dam/jcr:f8cfffe0-5383-4f89-ae5d-26e760dd68b8/huxley1932.png"
            },
            {
                "name": "sagan1997.png",
                "link": "/dam/jcr:a1a2ff1f-4580-4950-8576-0ec12ee35370/sagan1997.png"
            },
            {
                "name": "hawking2005.png",
                "link": "/dam/jcr:d5161c3b-2517-4476-9c18-c1c53886d555/hawking2005.png"
            },
            {
                "name": "hawking1988.png",
                "link": "/dam/jcr:f964ee41-d533-4a21-bb61-8c576498b868/hawking1988.png"
            },
            {
                "name": "darwin1859.png",
                "link": "/dam/jcr:da35e99f-6138-40c9-b7c1-57978aa70268/darwin1859.png"
            }
        ]
    }
}

Resolving asset renditions

To resolve asset renditions, renditions must be defined in a theme that is linked to a site definition. Let's assume you have the following theme definition called bookshelf-theme in the bookshelf light module:

<light-modules-folder>/bookshelf/themes/bookshelf-theme.yaml
imaging:
  class: info.magnolia.templating.imaging.VariationAwareImagingSupport
  variations:
    "1600":
      class: info.magnolia.templating.imaging.variation.SimpleResizeVariation
      width: 1600
    "1366":
      class: info.magnolia.templating.imaging.variation.SimpleResizeVariation
      width: 1366
    "240":
      class: info.magnolia.templating.imaging.variation.SimpleResizeVariation
      width: 240

The definition is linked to a site associated with the domain you query with GraphQL requests:

<site-name>:
  theme:
    name: bookshelf-theme

Then you can issue the following requests.

All renditions

{
    bookshelf(path: "/My-Good-Reads/Science/Darwin-1859-On-the-Origin-of-Species") {
        title
        frontcover {
            name
            link
            renditions {
                renditionName
                link
            }
        }
    }
}
 Click here to see the response ...
{
    "data": {
        "bookshelf": {
            "title": "On the Origin of Species by Means of Natural Selection, or the Preservation of Favoured Races in the Struggle for Life",
            "frontcover": {
                "name": "darwin1859.png",
                "link": "/dam/jcr:da35e99f-6138-40c9-b7c1-57978aa70268/darwin1859.png",
                "renditions": [
                    {
                        "renditionName": "1600",
                        "link": "/.imaging/mte/bookshelf-theme/1600/dam/Book-Covers/darwin1859.png/jcr:content/darwin1859.png"
                    },
                    {
                        "renditionName": "1366",
                        "link": "/.imaging/mte/bookshelf-theme/1366/dam/Book-Covers/darwin1859.png/jcr:content/darwin1859.png"
                    },
                    {
                        "renditionName": "240",
                        "link": "/.imaging/mte/bookshelf-theme/240/dam/Book-Covers/darwin1859.png/jcr:content/darwin1859.png"
                    }
                ]
            }
        }
    }
}

One rendition

{
    bookshelf(path: "/My-Good-Reads/Science/Darwin-1859-On-the-Origin-of-Species") {
        title
        frontcover {
            name
            link
            renditions(renditionNames: "1600") {
                renditionName
                link
            }
        }
    }
}
 Click here to see the response ...
{
    "data": {
        "bookshelf": {
            "title": "On the Origin of Species by Means of Natural Selection, or the Preservation of Favoured Races in the Struggle for Life",
            "frontcover": {
                "name": "darwin1859.png",
                "link": "/dam/jcr:da35e99f-6138-40c9-b7c1-57978aa70268/darwin1859.png",
                "renditions": [
                    {
                        "renditionName": "1600",
                        "link": "/.imaging/mte/bookshelf-theme/1600/dam/Book-Covers/darwin1859.png/jcr:content/darwin1859.png"
                    }
                ]
            }
        }
    }
}

Selected renditions

{
    bookshelf(path: "/My-Good-Reads/Science/Darwin-1859-On-the-Origin-of-Species") {
        title
        frontcover {
            name
            link
            renditions(renditionNames: ["1600","240"]) {
                renditionName
                link
            }
        }
    }
}
 Click here to see the response ...
{
    "data": {
        "bookshelf": {
            "title": "On the Origin of Species by Means of Natural Selection, or the Preservation of Favoured Races in the Struggle for Life",
            "frontcover": {
                "name": "darwin1859.png",
                "link": "/dam/jcr:da35e99f-6138-40c9-b7c1-57978aa70268/darwin1859.png",
                "renditions": [
                    {
                        "renditionName": "1600",
                        "link": "/.imaging/mte/bookshelf-theme/1600/dam/Book-Covers/darwin1859.png/jcr:content/darwin1859.png"
                    },
                    {
                        "renditionName": "240",
                        "link": "/.imaging/mte/bookshelf-theme/240/dam/Book-Covers/darwin1859.png/jcr:content/darwin1859.png"
                    }
                ]
            }
        }
    }
}

Paging

Paging of results in Magnolia GraphQL can be achieved using the limit and offset arguments. In the following body definition, only the first four entries for the title field are requested:

{
    bookshelves(limit: 4) {
        title
    }
}
 Click here to see the response ...
{
    "data": {
        "bookshelves": [
            {
                "title": "The War of the Worlds"
            },
            {
                "title": "Contact"
            },
            {
                "title": "On the Origin of Species by Means of Natural Selection, or the Preservation of Favoured Races in the Struggle for Life"
            },
            {
                "title": "A Brief History of Time: From the Big Bang to Black Holes"
            }
        ]
    }
}

With limit and offset set to 2 and 1, respectively, titles two and three are delivered:

{
    bookshelves(limit: 2, offset: 1) {
        title
    }
}
 Click here to see the response ...
{
    "data": {
        "bookshelves": [
            {
                "title": "Contact"
            },
            {
                "title": "On the Origin of Species by Means of Natural Selection, or the Preservation of Favoured Races in the Struggle for Life"
            }
        ]
    }
}

Sorting

For scalar JCR-based GraphQL types, Magnolia automatically generates custom ENUMs in the form <FIELDNAME>_ASC and <FIELDNAME>_DESC. These ENUMs then describe the fields that can be sorted. Field names must be given in the upper case form.

{
    bookshelves(sort: TITLE_DESC) {
        title
    }
}
 Click here to see the response ...
{
    "data": {
        "bookshelves": [
            {
                "title": "The War of the Worlds"
            },
            {
                "title": "On the Origin of Species by Means of Natural Selection, or the Preservation of Favoured Races in the Struggle for Life"
            },
            {
                "title": "God Created the Integers: The Mathematical Breakthroughs That Changed History"
            },
            {
                "title": "Contact"
            },
            {
                "title": "Brave New World"
            },
            {
                "title": "A Brief History of Time: From the Big Bang to Black Holes"
            }
        ]
    }
}

You can also chain the sort operations, for example sort: [AUTHOR_ASC, TITLE_ASC] first sorts the results by the author property and then by the title property.

Filtering

To filter the results, you can use a number of simple filters and operators that can be chained using the AND and OR conjunctions into a multiple predicate. The conjunctions can be used in either case, lower or upper. In case of JCR, AND has precedence before OR. Parentheses,( and ), can be used for grouping the filters.

Example filter requesting title fields that contain "War" or "Struggle": 

{
    bookshelves(filter: "@title LIKE '%War%' OR @title LIKE '%Struggle%'") {
        title
    }
}
 Click here to see the response ...
{
    "data": {
        "bookshelves": [
            {
                "title": "The War of the Worlds"
            },
            {
                "title": "On the Origin of Species by Means of Natural Selection, or the Preservation of Favoured Races in the Struggle for Life"
            }
        ]
    }
}

Filters

Numbers

Number matching is done against the type stored in the repository.

  • Integers (longs in case of JCR):
    • filter: "@bar = 123"
  • For floats (doubles in case of JCR), use  the floating-point format or the f suffix:
    • filter: "@bar = 123.0"
    • filter: "@bar = 123f"
    • filter: "@bar = 123.0f"
  • For big decimals (decimals in case of JCR), use the D suffix:
    • filter: "@bar = 123D"
    • filter: "@bar = 123.0D"

Booleans

For booleans, use either true or false. Both cases are allowed:

  • filter: "@foo = true"
  • filter: "@foo = FALSE"

Nulls

Nulls can also be declared in both cases. For JCR-stored data, these are property existence checks, not empty value checks.

  • filter: "@foo = null"
  • filter: "@foo <> NULL"

Strings

Strings must be enclosed in single quotes:

  • filter: "@foo = 'Some String'"

JCR implementation recognizes the ISO8601 format with time zones:

  • filter: "@fooDate = '2019-02-11T00:00:00+02:00'"

To search within a string, use the percentage sign with the LIKE operator:

  • filter: "@foo LIKE '%World%'"

Property names

A name must start with the at sign (@) and must match the [_A-Za-z] [_0-9A-Za-z] pattern. Only one nested level is supported for names and subtype names.

  • filter: "@stats.speed = 200"

In case of JCR, this will create a condition that tries to filter against a submodel named stats and its speed property 

Operators

FormMeaning
=equal
<>not equal
>greater than
<lesser than
<=lesser than or equal
>=greater than or equal

LIKE

Can be used with:

  • Percentage sign (%) - Wildcard character that can be used in the search pattern to mean zero or more additional characters.
like

See also

ISO 8601 — Date and time format

Metadata

It is possible to request metadata for the content, data that is in the system, but is not explicitly declared in the content type.

By default, 4 properties are available: id, name, path, nodeType

They can be retrived from the `_metadata` property.

_metadata example
{
  book(id: 1) {
    title
    isbn13
    _metadata {
      id
      name
      path
      nodeType
    }
  }
}
 

Retrieving additional meta properties

Which properties are available is configurable.

An example of configuring an addtional `created` field which returns `mgnl:created` property via the decoration mechanism:

With path: 
/<my-light-module>/decorations/graphql-jcr/graphqlTypes/jcrMetadata.types.JcrMetadata.yaml

fields:
  - name: 'created'
    type:
      name: Date
      nonNull: true
    dataFetcher:
      class: info.magnolia.graphql.jcr.datafetcher.JcrPropertyDataFetcherDefinition
      propertyName: 'mgnl:created'