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
{
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.
subscription {
event {
type
dataAsJson
}
}
Starting from Guillotine listens to node events only for a specific repository and branch of the site.
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
.
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
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
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 |
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).
{ guillotine { get { displayName children { displayName } } } }
{ 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.
{ 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.
{ 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.