dot CMS

Mastering dotCMS Content API Integration with Next.js

dotCMS

Share this article on:

dotCMS, the top Universal Content Management System, provides powerful content management features for modern web applications. This guide explains how to use the dotCMS content API in a Next.js application, boosting your site’s dynamic capabilities, content flexibility, and SEO.

By integrating dotCMS with Next.js, you'll be able to:

  • Create highly dynamic and responsive web applications

  • Manage content efficiently through dotCMS's intuitive interface

  • Leverage Next.js' server-side rendering for improved SEO

  • Achieve faster load times and better performance

Setting Up the dotCMS Client

Installation

First, you need to install the @dotcms/client library in your Next.js project:

npm install @dotcms/client --save

Initialization

Then import and initialize the client with your dotCMS host and authentication token to connect to your dotCMS instance:

import { dotcmsClient } from "@dotcms/client";
const client = dotcmsClient.init({
    dotcmsUrl: process.env.NEXT_PUBLIC_DOTCMS_HOST,
    authToken: process.env.NEXT_PUBLIC_DOTCMS_AUTH_TOKEN,
});

Make sure to set the NEXT_PUBLIC_DOTCMS_HOST and NEXT_PUBLIC_DOTCMS_AUTH_TOKEN in your .env.local file:

NEXT_PUBLIC_DOTCMS_HOST=https://your-dotcms-instance.com

NEXT_PUBLIC_DOTCMS_AUTH_TOKEN=your-auth-token

Important Security Note: Ensure that the auth token used has only read permissions to minimize security risks in client-side applications.

Building your dynamic component

Let's create a dynamic blog list component that fetches and displays the latest blog posts from dotCMS.

Creating the BlogList Component

Create a new file components/BlogList.js:

import { useState, useEffect } from 'react';
import client from '../dotcmsClient';
import BlogItem from './BlogItem';
export default function BlogList() {
    const [blogs, setBlogs] = useState([]);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    useEffect(() => {
        fetchBlogs();
    }, []);
    const fetchBlogs = async () => {
        try {
            const response = await client.content
                .getCollection("Blog")
                .sortBy([{ field: "modDate", order: "desc" }])
                .limit(3)
                .fetch();
            setBlogs(response.contentlets);
            setLoading(false);
        } catch (error) {
            console.error(`Error fetching Blogs`, error);
            setError('Failed to fetch blogs. Please try again later.');
            setLoading(false);
        }
    };
    if (loading) return <div>Loading...</div>;
    if (error) return <div>{error}</div>;
    return (
        <div className="flex flex-col">
            <h2 className="text-2xl font-bold mb-7 text-black">Latest Blog Posts</h2>
            <ul className="space-y-4">
                {blogs.map(contentlet => (
                    <li key={contentlet.identifier}>
                        <BlogItem data={contentlet} />
                    </li>
                ))}
            </ul>
        </div>
    );
}

Creating the BlogItem Component

Now, let's create the BlogItem component in components/BlogItem.js:

import Image from 'next/image';
export default function BlogItem({ data }) {
    const dateFormatOptions = { year: 'numeric', month: 'long', day: 'numeric' };
    return (
        <div className="flex items-center space-x-4">
            <div className="relative w-32 h-32">
                <Image
                    src={`${process.env.NEXT_PUBLIC_DOTCMS_HOST}${data.image}?language_id=${data.languageId || 1}`}
                    alt={data.urlTitle}
                    layout="fill"
                    objectFit="cover"
                    className="rounded-lg"
                />
            </div>
            <div className="flex flex-col">
                <a 
                    href={data.urlMap || data.url}
                    className="text-lg font-semibold text-zinc-900 hover:underline"
                >
                    {data.title}
                </a>
                <time className="text-sm text-zinc-600">
                    {new Date(data.modDate).toLocaleDateString(
                        "en-US",
                        dateFormatOptions
                    )}
                </time>
                <p className="mt-2 text-zinc-700">{data.description}</p>
            </div>
        </div>
    );
}

Using the Components

You can now use the BlogList component in any of your pages. For example, in your pages/index.js:

import BlogList from '../components/BlogList';
export default function Home() {
    return (
        <div className="container mx-auto px-4 py-8">
            <h1 className="text-4xl font-bold mb-8">Welcome to Our Blog</h1>
            <BlogList />
        </div>
    );
}

Best Practices and Optimizations

  1. Error Handling: Always implement robust error handling to manage API failures gracefully or unexpected responses.

  2. Loading States: Provide clear loading indicators to improve user experience while content is being fetched.

  3. Pagination: For larger collections, implement pagination to improve performance and user experience.

  4. SEO Optimization: Leverage Next.js' server-side rendering capabilities for better SEO.

  5. Caching: Implement caching strategies to reduce API calls and improve performance.

  6. Type Safety: If using TypeScript, define interfaces for your content types to improve type safety and developer experience.

Conclusion

The dotCMS content API is a powerful tool that allows you to retrieve content of any kind, with flexible filtering and pagination options. Integrating the dotCMS content API with Next.js opens up a world of possibilities for creating dynamic, content-rich web applications.

You now know the basics of setting up the dotCMS client, creating dynamic components, and fetching content!