03 November 2016

Written by Andrea Rosati

Introduction

Confluence provides creation and collaboration features for different types of content like Spaces, Pages, Attachments, Comments, etc... and all these contents are supported by default within Confluence. It is also possible to create new customised types of content that integrate with Confluence

Just like with the default content types the custom content types behave the same and they integrate tightly with Confluence features such as Search and Navigation, in addition to having the API capabilities of default Confluence content.

For the purpose of explaining custom content entities I'm going to show the implementation we use in Forms for Confluence Connect plugin. In this post I'm not giving much attention on UI elements, but it is more a discussion about how to configure and use custom content entities.

Configuration

To declare custom content we need to add the module to our atlassian-connect.json plugin descriptor. The example below only shows the main parts to configure as to stay in scope of this discussion.

  "modules": {
    "customContent": [
      {
        "key": "formconfig",
        "name": {
          "value": "Form Configurations"
        },
        "uiSupport": {
          ...
        },
        "apiSupport": {
          "supportedContainerTypes": [
            "space"
          ],
          "supportedChildTypes": [
            "ac:com.adaptavist.confluence.formMailNG:formresponse"
          ]
        }
      },
      {
        "key": "formresponse",
        "name": {
          "value": "Form Responses"
        },
        "uiSupport": {
          ...
        },
        "apiSupport": {
          "supportedContainerTypes": [
            "ac:com.adaptavist.confluence.formMailNG:formconfig"
          ],
          "supportedChildTypes": [],
          "indexing": {
            "enabled": false
          }
        }
      }
    ],
    ...
  }

We started defining two different custom contents: 'Form Configurations' and 'Form Responses'. They both have a unique key and both define a parent-child relationship.

Form Configurations are children of a Space and contain Form Responses.

Form Responses can be contained within a Form Configuration, and that a Form Response is indeed a supported child type of a Form Configuration.

The content type key for custom content is defined in 3 parts:

  • ac: This is always the same, indicating that this content type is defined in a Connect add-on.

  • addon-key: The key of the Connect add-on

  • custom-content: The key of the module which defines the custom content

CRUD actions

Because custom content is directly organised and maintained by Confluence, it can be created, retrieved, updated or deleted using the Confluence REST API. I think that is the most powerful feature of the custom content; the API basically permit us to throw away the database layer and we don't have to spend time to maintain all the different DBMS the clients have.

Following I'm going to show some examples of how the custom content entities are used within Forms for Confluence Connect plugin. The examples will focus on the request itself, nothing is specified on how to handle the response given back from Confluence.

Create

Here's a POST request that is going to store new data in Confluence. In particular we're going to save a Form Configuration with:

  • title
  • description
  • space
  • version
  • type

The type is going to specify to Confluence that the new entity is our customized content type.

var newFormConfigTitle = AJS.$('#formId').val();
AP.require('request', function (request) {
  request({
    url: '/rest/api/content',
    type: 'POST',
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    data: JSON.stringify({
      version: {
        number: 1
      },
      title: newFormConfigTitle,
      type: "ac:com.adaptavist.confluence.formMailNG:formconfig",
      space: {
        key: getUrlParam('space_key')
      },
      body: {
        storage: {
          value: AJS.$('#formDescription').val(),
          representation: "storage"
        }
      }
    })
  });
});

Get

To get all the Form Configurations children of a space, here is the simple request.

AP.require('request', function (request) {
  request({
    url: '/rest/api/content?type=ac:com.adaptavist.confluence.formMailNG:formconfig' +
          '&spaceKey=' + getUrlParam('space_key'),
    type: 'GET',
    contentType: "application/json; charset=utf-8"
  });
});

Delete

And finally how to delete a Form Configuration.

AP.require('request', function (request) {
  request({
    url: '/rest/api/content/' + formConfigId,
    type: 'DELETE',
    contentType: 'application/json'
  });
});

As we have seen the actions to interact with a custom content entity are very simple. More details related to Confluence API can be found at Confluence Cloud REST API Reference.

Index

Custom content types are indexed as a built-in content type and rendered in quick search and site-wide search. The default value is true, so your custom content type will automatically be indexed if you don't specify a value.

In the following example when we search for the string 'bar' we receive back a list of Form Configurations that match the search condition.

Conclusion

As we have seen custom content well and truly provides a fully-integrated content solution within Confluence. The most interesting benefit I found so far is that we completely dropped the database layer in our architecture. This means there is no time spent to configure a database connection or to fix compatibility problems with one dbms compared to another one. A possible drawback can be that a normal database connection is more flexible and permits easier migrations. I cannot compare the two different solutions now because I didn't need to perfom any migration so far.



blog comments powered by Disqus