Guillotine - Headless CMS

Contents

Guillotine - Headless CMS

Guillotine exposes the read-only part of the Enonic Content API, including access to the Enonic query language. Guillotine dynamically analyzes all available content types and generates a GraphQL API specific to your site. This gives you direct, typed and documented access to all content within the site. Including the ability to follow references, child items and access media directly.

Usage

The fastest way to set up Guillotine is to download the Guillotine application and associate it to your site.

But depending on what you intend to achieve, you might prefer using the Guillotine library inside your application instead. You will want to use the library if:

  • You want your application to be standalone and not require the installation of another application

  • You want to extend or modify the GraphQL API generated by Guillotine

Guillotine application

Step 1: Installation

  • Open the admin tool "Applications"

  • Search for the "guillotine" application

  • Click on "install"

Installation

Step 2: Configuration

  • Open the admin tool "Content Studio"

  • Edit your site

  • Add the application "Guillotine"

You now have a GraphQL endpoint!

Installation

Guillotine library

Step 1: Include the library

  • Check that the Enonic repository is in the list of repositories

repositories {
  maven {
    url 'https://repo.enonic.com/public'
  }
}
  • Add the following dependency (where <version> is the actual version to use):

dependencies {
  include 'com.enonic.lib:lib-guillotine:<version>'
}

Step 2: Create a GraphQL endpoint

  • Create an Enonic XP service file /services/graphql/graphql.js with the following content:

/services/graphql/graphql.js
var guillotineLib = require('/lib/guillotine'); (1)
var graphQlLib = require('/lib/graphql'); (1)

var schema = guillotineLib.createSchema(); (2)

exports.post = function (req) { (3)
 var body = JSON.parse(req.body); (4)
 var result = graphQlLib.execute(schema, body.query, body.variables); (5)
 return {
     contentType: 'application/json',
     body: result
 };
};
1 Requires the Guillotine and GraphQL libraries. The GraphQL library is already included with Guillotine and does not need to be added to your Gradle file
2 Creates the GraphQL schema the first time the service is called.
3 Handles POST requests
4 Parses the JSON body to retrieve the GraphQL query and variables
5 Executes the query and variables against the schema created

You now have a GraphQL endpoint!

Browse you API using GraphiQL

The easiest way to manually explore a GraphQL API and test GraphQL queries is to use GraphiQL

GraphQL is a query language developed by Facebook. This technology allows Guillotine to provide a single and exhaustive API while allowing you to retrieve all the content information you need in one request without any superfluous information

Installation

  • Open the admin tool "Applications"

  • Search for the "graphiql" application

  • Click on "install"

  • Open the admin tool "GraphiQL"

GraphiQL

User 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.

Usage example

By default, 'Service Location' is prefilled with the URL of the service 'graphql' for one of your configured sites for the branch "draft".

To determine the URL of your service:

  • If you are using the Guillotine application, the URL will be: [site-url]/_/service/com.enonic.app.guillotine/graphql

    • Example: http://localhost:8080/portal/draft/superhero/_/service/com.enonic.app.guillotine/graphql

  • If you are using the Guillotine library, the URL will be: [site-url]/_/service/[application]/[service-name]

    • Example: http://localhost:8080/portal/draft/superhero/_/service/com.enonic.app.superhero/graphql

  • 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

{
  guillotine {
    get {
      displayName
      type
    }
  }
}
Example

Accessing the API 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, MediaUploader, AttachmentUploader 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})
        }
      }
    }
  }
}

Contents