dot CMS

Building a Content Management Interface with dotCMS REST APIs: A Developer's Guide

Building a Content Management Interface with dotCMS REST APIs: A Developer's Guide
Author image

Daniel Silva

Software Engineer Manager

Share this article on:

Modern enterprises need flexible content management solutions that can be integrated into any tech stack. dotCMS offers powerful REST APIs that enable developers to create, manage, and deliver content programmatically. In this blog post, we'll build a content management interface built to demonstrate three key dotCMS APIs in action, showing you how to create a robust content management workflow.

Understanding dotCMS REST APIs

Before diving into implementation, let's examine the core APIs we'll be working with:

1. Content Type API

  • Defines content structure and fields

  • Handles field validation rules

2. Workflow API

  • Controls content lifecycle

  • Manages publishing states

  • Handles content versioning

3. Content API

  • Retrieves content with advanced filtering

  • Supports pagination and sorting

  • Enables content search capabilities

Setting Up the Development Environment

While our focus is on the dotCMS APIs, we'll clone a React application tailored to demonstrate their usage. Here's how to set up the project:

# If you've already initialized a dotCMS examples repo directory, skip this step; otherwise, navigate to the desired directory and run the following commands:

git init

git remote add -f origin https://github.com/dotCMS/examples.git

git sparse-checkout init



# Clone this demo's subdirectory from the repo:

git sparse-checkout set rest-api-demo $(git sparse-checkout list) --no-cone

git pull origin main



# Finally, run the project:

cd rest-api-demo

npm i

npm run dev

To get the demo app working we need to include this environment variable:

VITE_DOTCMS_API_TOKEN={your-dotcms-api-token}

In order to get an API token please follow this link: https://www2.dotcms.com/docs/latest/rest-api-authentication#APIToken

The Application in Action

Our demo application provides an intuitive interface for interacting with dotCMS's REST APIs. Let's walk through its key features:

Content Type Management

image1.png
image2.png

The home screen presents two core functionalities powered by the Content Type API:

  • A creation form for new content types

  • A list of existing content types with their actions

  • Each content type includes a "Create Content" action that demonstrates API chaining

Content Creation Flow

image3.png

The content creation interface showcases the Workflow API in action, with text and Block Editor fields demonstrating field type flexibility. The real-time content list updates after successful creation.

Content Management

image4.png

The right panel displays created content, retrieving content immediately after publishing. This real-time list updates using the Content API.

This implementation demonstrates key dotCMS API capabilities:

  • Content type creation and management

  • Content publishing workflow

  • Real-time content retrieval and display

The interface provides enterprise developers with a practical example of integrating dotCMS APIs into modern web applications while maintaining a clean, user-friendly experience.

Source Code Access

The complete source code for this demo application is available in the dotCMS examples repository: https://github.com/dotCMS/examples/tree/main/rest-api-demo

The repository includes all components and configurations shown in this tutorial, making it easy to review, practice, or otherwise learn in a variety of ways:

  • Explore the API integration patterns

  • Test different content type configurations

  • Adapt the code for your own projects

  • Understand best practices for dotCMS API implementation

Deep Dive: Content Type API

The Content Type API is fundamental to content management in dotCMS. Let's explore its capabilities, starting with a typical call and payload.

Creating a Content Type

POST /api/v1/contenttype

{

  "clazz": "com.dotcms.contenttype.model.type.ImmutableSimpleContentType",

  "host": "SYSTEM_HOST",

  "folder": "SYSTEM_FOLDER",

  "name": "demo-apis-blog-post",

  "fields": [

    {

      "clazz": "com.dotcms.contenttype.model.field.TextField",

      "indexed": true,

      "required": true,

      "name": "title",

      "variable": "title"

    },

    {

      "clazz": "com.dotcms.contenttype.model.field.ImmutableStoryBlockField",

      "name": "block",

      "searchable": true

    }

  ]

}

Key aspects of the Content Type API include their direct properties, their field types, and their field properties.

Field Types

dotCMS has many standard content field types. We’ll be working with just a few of them. 

Field types are specified by their class, which by Java convention corresponds to a “clazz” property. The simplest way to fetch a list of possible class values is through the fieldTypes endpoint, which requires no parameter:

GET /api/v1/fieldTypes

So, for example, the text field is specified by “com.dotcms.contenttype.model.field.ImmutableTextField”; all other clazz values begin the same way, with “com…Immutable,” so we’ll give one full-length example, and then a few more that have been shortened for ease of reading:

  • com.dotcms.contenttype.model.field.ImmutableTextField: The Text field, for basic text content

  • com…ImmutableStoryBlockField: The Block Editor, for rich content editing

  • …DateField: For temporal data

  • …KeyValueField: For non-structured information of various sorts

  • …RelationshipField: For content relationships

Each field has its own field properties that indicate how it should be treated within the context of the system, such as:

  • required: Makes field mandatory, such that content cannot be saved if it is blank.

  • indexed: If true, this field will be included in the system index.

  • searchable: Allows searching of content within the field

  • listed: Shows field directly in content search result listing page

Finally, there are properties that apply to entire content types at once:

  • host: Associates with a specific site

  • workflow: Links to workflow schemes (see below for more on this)

Workflow API: Content Lifecycle Management

The Workflow API handles content state transitions through user-defined workflow actions. Here's an example call meant to publish content:

PUT /api/v1/workflow/actions/default/fire/PUBLISH

{

  "contentlet": {

    "contentType": "demo-apis-blog-post",

    "title": "My First Post",

    "block": {

      "type": "doc",

      "content": [{

        "type": "paragraph",

        "content": [{

          "type": "text",

          "text": "Article content goes here"

        }]

      }]

    }

  }

}

Workflow States and Actions

When using workflows, you’ll commonly be calling default actions. There are eight default actions available — such as NEW, EDIT, PUBLISH, UNPUBLISH, etc. — and each content type assigns workflow actions to these defaults separately. In this way, two content types may react to the same PUBLISH call with different underlying actions, to better suit their individual needs. 

PUT /api/v1/workflow/actions/{workflowId}/fire/{actionId}

{

  "contentlet": {

    // content data

  },

  "comments": "Ready for review",

  "assignTo": "editor@company.com"

}

Content API: Advanced Querying

The Content API supports sophisticated content retrieval:

GET /api/v1/contenttype?per_page=100&orderby=modDate DESC

GET /api/content/render/false/query/+contentType:blog-post +working:true

Above, we can see calls that respectively fetch content types and contentlets — or, individual units of content. (In programming terms: Content types relate to contentlets as classes to objects.)

The examples above show an example of the use of both query and path parameters. Queries themselves use the Lucene syntax.

Some parameters may include, though are not limited to:

  • per_page: Results per page

  • orderby: Sorting criteria — an indexed field or system variable, followed by ASC or DESC for ascending or descending

  • query: Lucene query syntax

  • depth: Related content depth

The following query, which is a little more complex, returns blog post contentlets of the “tech” category, published within a date range:

// Complex query example

GET /api/content/render/false/query/+contentType:blog-post +categories:tech +publishDate:[20240101 TO 20241231]

Implementing the Interface

Our demo application provides two main views:

  1. Content Type Creation

const CreateContentType = () => {

  const handleSubmit = async (e) => {

    e.preventDefault();

    const response = await fetch('/api/v1/contenttype', {

      method: 'POST',

      headers: {

        'Content-Type': 'application/json',

        'Authorization': Bearer ${token}

      },

      body: JSON.stringify({

        // Content type definition

      })

    });

    // Handle response

  };

  // Component JSX

};
  1. Content Management

const CreateContent = () => {

  const handlePublish = async (content) => {

    const response = await fetch('/api/v1/workflow/actions/default/fire/PUBLISH', {

      method: 'PUT',

      headers: {

        'Content-Type': 'application/json',

        'Authorization': Bearer ${token}

      },

      body: JSON.stringify({

        contentlet: content

      })

    });

    // Handle response

  };

  // Component JSX

};

Enterprise Implementation Considerations

1. Authentication and Security

For an alternate way to handle tokens, the following endpoint provides a simple interface.

// JWT token handling

const getAuthToken = async () => {

  const response = await fetch('/api/v1/authentication/api-token', {

    method: 'POST',

    headers: {

      'Content-Type': 'application/json'

    },

    body: JSON.stringify({

      user: 'api-user',

      password: 'secure-password',

      expirationDays: '10'

    })

  });

  return response.json();

};

2. Error Handling

const handleApiError = (error) => {

  if (error.response) {

    switch (error.response.status) {

      case 401:

        // Handle authentication error

        break;

      case 403:

        // Handle permissions error

        break;

      case 404:

        // Handle not found

        break;

      default:

        // Handle other errors

    }

  }

};

3. Performance Optimization

Some ideas to get the most out of your hardware might include:

  • To prevent excessive API calls, you may want to try one of the following tactics:

    • Caching frequent calls according to your implementation — for example, here are some guidelines for Next.JS

    • Implement request debouncing to limit the speed with which they’re sent

  • Use pagination — built in to all REST API calls — for large content sets

4. Monitoring and Logging

When in doubt, never be afraid to log anything and everything.

const logApiRequest = (endpoint, method, data) => {

  console.log(`API ${method} ${endpoint}`, {

    timestamp: new Date(),

    data,

    user: getCurrentUser()

  });

};

Conclusion

dotCMS's REST APIs provide a robust foundation for building custom content management solutions. The combination of the Content Type API, Workflow API, and Content API enables developers to create flexible, scalable content management systems that can be integrated into any enterprise architecture.

This implementation demonstrates how to:

  • Create structured content types

  • Manage content lifecycle

  • Implement secure content operations

  • Build user-friendly interfaces

For enterprise developers, the key advantages include:

  • Full programmatic control over content

  • Flexible integration capabilities

  • Scalable content operations

  • Secure content management

For complete API documentation and advanced features, visit the dotCMS API Documentation.

Additional Resources