Using the GraphQL API

Contents

This section describes how access and use the GraphQL API

Introduction

GraphQL is a query language developed by Facebook. Compared to RESTful APIs, GraphQL is strongly typed and self-documented. It also enable client developers to request exactly the information required in as few requests as possible.

Sites

A site in Enonic XP represents main container of content, while being a content item itself.

In addition to being a content container, a site may also have applications assigned to it. An application defines content types and potentially other capabilities (macros, filters, extra-data etc.) that will be added to the site along with the app.

Context

All XP sites have a specific endpoint that can be accessed through an internal URL pattern. This pattern combined, provides what we call the context.

For instance, a typical internal site URL may look like this:

It consists of the following elements:

<scheme>://<host>:<port>/<engine>/<project>/<branch>/<sitepath>

Every part of this URL composes the context. In our case, we are specifically interested in the project, branch and sitepath.

Project

Determines the underlying CMS repo being accessed

Branch

Determines branch: Allowed values are 'draft' or 'master' (where master represents the published data set)

Sitepath

Must match the path to the specific site to access

Using different project, branch and site path enable us to access different sites, in different modes. For instance accessing the draft content (i.e. for a preview application), or for accessing the "live" content of the master branch.

Vhosts

Since any XP instance may contain multiple sites, vhosts provide a way of exposing your APIs through a "nice" URL.

As an example, mysite.com may be configured to point to the internal path /site/default/master/path-to/mysite - this way end-users will only see mysite.com, but internally the entire context is still available and in use.

Also, draft.mysite.com may point to /site/default/draft/path-to/mysite - and be secured or exposed only to internal preview applications.

For more details about vhosts, check out the XP documentation

GraphQL Playground

The Guillotine app ships with an embedded GraphQL browser called GraphQL Playground. This enables you to instantly access and communicate with the API. When setting up Guillotine as a library, you can choose to embed GraphQL playground or not.

We recommend embedding a GraphQL browser with the API, as this greatly simplifies developers access to and use of the API.

Interface

  • The field 'Service Location' specifies the location of the GraphQL service.

  • The left panel allows you to edit your graphQL query

  • The center panel displays the result of the query execution

  • The right panel is used to display a documentation generated from the GraphQL API.

Sample query

  • Write the query below inside the left panel.

    This query can be read as: Retrieve the display name and type of the current content.

  • Click on the query execution button above

  • The service response is displayed in the center panel

getSite
{
  guillotine {
    getSite {
      displayName
      type
    }
  }
}

Sample subscription

Guillotine also enables you to use GraphQL subscription in order to listen to events from the server.

The subscriptions are implemented using Websockets, providing instant and high performance streaming of events over HTTP.

Listen to server events for the specific site
subscription {
  event {
    type
    dataAsJson
  }
}

Starting from v v 5.0.0 5.0.0 Guillotine listens to node events only for a specific repository and branch of the site.

Provide branch, repositoryId and siteId in the data object for WebSocket request:
const portalLib = require('/lib/xp/portal');

webSocket: {
    data: {
        branch: req.branch,
        repositoryId: req.repositoryId,
        siteId: portalLib.getSite()._id
    },
    subProtocols: ['graphql-ws']
}

or use the guillotineLib.createWebSocketData(req) method which is available starting from v v 5.1.0 5.1.0 .

webSocket: {
    data: guillotineLib.createWebSocketData(req),
    subProtocols: ['graphql-ws']
}

Only node.* events are listened to by default. In order to configure which events should be listened to by an application or a site the subscriptionEventTypes option must be specified on schema creation, in this case default config will be overwritten.

var guillotineLib = require('/lib/guillotine');

var SCHEMA = guillotineLib.createSchema({
    subscriptionEventTypes: ['myapp.eventName', 'node.*']
});

To start handle a Websocket event XP provides the handler named webSocketEvent, which will be called for every Websocket event from client. More details about Websocket in XP here.

Starting from v v 5.0.0 5.0.0 Guillotine provides the initWebSockets function with default events handling.

exports.webSocketEvent = guillotineLib.initWebSockets(SCHEMA);

You might want to have custom subscriptions handling. If default events filtering is not suitable for you, then you have to create own Subscription type during a schema creation and implement a custom webSocketEvent handler how it was done before.

Accessing GraphQL with Javascript

To use your GraphQL service, your client will send all its requests to the same service. The service is expecting to receive a POST request with inside its body:

  • A mandatory "query" String

  • An optional "variables" Object

Example: Generate the service URL from a controller
var portalLib = require('/lib/xp/portal');
var graphqlServiceUrl = portalLib.serviceUrl({
    service: 'graphql',
    application: 'com.enonic.app.guillotine' (1)
});
1 Remove this line if you are using the guillotine library
Example: Fetch data from a javascript client
const query = `query($path:ID!){
    guillotine {
        get(key:$path) {
            displayName
            type
        }
    }
}`;

const variables = {
    'path': '/mysite/mycontentpath'
};

fetch('{{graphqlServiceUrl}}', {
    method: 'POST',
    body: JSON.stringify({
        query: query,
        variables: variables
    }),
    credentials: 'same-origin'
})
    .then(response => response.json())
    .then(console.log);

Using the API

At the root of the default Guillotine schema is a type Query with a field guillotine of type HeadlessCms. The HeadlessCms type gathers fields allowing to retrieve contents or related data.

Content

The type Content is an interface with multiple implementations generated from built-in content types but also from content types defined by your application. All types implementing Content share the same fields at the exception of the field data defined for each implementation type.

Relations

Multiple relations are generated to allow to navigate between contents. By default, each content has the following relations:

  • parent: Link to the parent content

  • children: Link to the child contents

  • site: Link to the nearest site content

Moreover, every ContentSelector, MediaSelector or ImageSelector defined in your content type form will be converted to a link to the related content(s).

Query example: Retrieve the display name of the current content and the display name of its direct children
{
  guillotine {
    get {
      displayName
      children {
        displayName
      }
    }
  }
}
Query example: Retrieve the blog posts. For each post, return its display name and the display name of the related author
{
  guillotine {
    query(contentTypes:"com.enonic.app.myapp:post") {
      displayName
      ... on com_enonic_app_myapp_Post {
        data {
          author {
            displayName
          }
        }
      }
    }
  }
}

Image

Enonic XP can edit images at runtime. Guillotine uses this functionality by generating, on every image, a field "imageUrl" generating a URL pointing to the processed image.

Example: Scaled Image URL - Retrieve the image contents and generate absolute URLs to these images cropped to 800x200px
{
  guillotine {
    query(contentTypes:"media:image") {
      displayName
      ... on media_Image {
        imageUrl(scale:"block(800,200)",type:absolute)
      }
    }
  }
}

HTML

HTML fields are generated with a parameter "processHtml" allowing to replace abstract internal links by generated URLs.

Example: Process HTML - Retrieve the Superhero blog posts. For each post, return its author display name, tags and processed content.
{
  guillotine {
    query(contentTypes:"com.enonic.app.myapp:post") {
      ... on com_enonic_app_myapp_Post {
        data {
          author {
            displayName
          }
          tags
          post(processHtml:{type:absolute}) {
             raw
             processedHtml
          }
        }
      }
    }
  }
}

More details about HTML processing.


Contents

Contents