In this article, you will learn how to create a Next.js application integrated with Flotiq. We will describe how to conveniently fetch data using a personalized SDK, configure caching, and utilize draft mode for previewing changes. Finally, we will publish the application on the Vercel platform.

The example application code can be found on GitHub.

Prerequisites

Before diving into the article, make sure that:

  • You have a Flotiq account.
  • You have a Vercel account.
  • You have basic knowledge of React.js, TypeScript, and Next.js.

Action Plan

In a few simple steps, we will create a real-world News page listing current news.

  1. Setup content types and data in Flotiq
  2. Setup the Next.js application
  3. Connect Flotiq with Next.js using a personalized SDK
  4. Display a list of articles and a single article
  5. Build a statically generated application
  6. Implement the On-demand revalidation mechanism
  7. Implement Next.js Draft Mode
  8. Go live! Deployment to Vercel

1. Setup Content Types in Flotiq

First, we need to create Content Type Definitions for our project. In the proposed example, this will be the Project data type.

1. Log in to the Flotiq panel.

2. Create a Content Type Definition corresponding to our project.

  • Label: Project
  • API Name: project
  • Properties:

3. Use the Slug plugin, to simplify content entry. This will automatically generate a slug from a specified field.

  • Go to Plugins.
  • Click “+” next to the Slug plugin.
  • Complete the configuration.

4. Enter sample data into Flotiq. A few sample entries will suffice:

The first important step is behind us. We now know what we will store in the system and can start adding content. Now it's time to prepare the application based on your model and data.

2. Next.js application setup

Navigate to the desired directory and run the following command to create a new Next.js application:

npx create-next-app@latest

We will create a project using the App Router, based on TypeScript, and utilizing Tailwind CSS as the CSS framework. Here is the complete configuration:

Navigate to the application directory and run the application

npm run dev

At http://localhost:3000, you will see the default Next.js homepage.

Now, it's time to add content from Flotiq.

3. Connecting Flotiq with Next.js using a personalized SDK

Data from Flotiq can be fetched in various ways - using REST API or GraphQL. Regardless of the approach taken, to communicate with Flotiq, we need to save the API Key in the application, which gives access to your data in Flotiq.

The API Key is available in the Flotiq panel, under the "API Keys" tab. Copy the "Read and write API KEY".

You can generate a key that includes only the necessary elements, e.g., the "Project" Content Type for reading. If the application in the future allows writing, such as comments, you can generate a key with the appropriate permissions.

Setting up environment variables

Create a .env.local file and paste the value copied from Flotiq into it.

FLOTIQ_API_KEY=___YOUR_READ_ONLY_API_KEY___

Setting up Flotiq SDK

In projects built with TypeScript, we recommend using the personalized Flotiq SDK. It wraps the REST API, providing convenient access to data tailored to your data model, including data types and intelligent code completion.

Download the Flotiq SDK for your project:

npx flotiq-codegen-ts@latest

Executing the command will download the SDK based on your Content Type Definitions. Note that the script used the previously pasted key from the .env.local file. A directory named flotiqApi has been created in your application directory.

Remember, when you change the Content Type Definition settings in Flotiq (e.g., add a new type or change a field in an existing one), you need to run the command again: npx flotiq-codegen-ts.

Fetch content from Flotiq using Flotiq SDK

Now let's dive into how to use the downloaded SDK. For the sake of organization, we will save the communication logic with Flotiq in a separate file /src/lib/api.ts.

Create a file /src/lib/api.ts where we will place the basic requests needed to complete the project:

import { FlotiqApi, Project, ProjectList } from "../../flotiqApi/src";

type ProjectFilter = {
  slug?: {
    type: string,
    filter: string
  }
}

export async function fetchAllProjects(): Promise<ProjectList> {
  const flotiq = new FlotiqApi(process.env.FLOTIQ_API_KEY);
  const filters: ProjectFilter = {};

  return flotiq.ProjectAPI.list({
    limit: 100,
    filters: JSON.stringify(filters)
  });
}

export async function fetchProjectBySlug(slug: string): Promise<Project | undefined> {
  const flotiq = new FlotiqApi(process.env.FLOTIQ_API_KEY);
  const filters: ProjectFilter = {
    slug: {
      type: 'equals',
      filter: slug,
    }
  };
  const projects = await flotiq.ProjectAPI.list({
    limit: 1,
    filters: JSON.stringify(filters)
  });
  return projects.data?.[0];
}

Note the following:

  • Line 10: The fetchAllProjects method retrieves all objects of the Project type.
  • Line 20: The fetchProjectBySlug method retrieves a Project object that has a specific value in the slug field.

Notice that in the code, we can use types such as ProjectList or Project, making it more convenient to work with data stored in Flotiq.

Now we are ready to display content from Flotiq.

4. Displaying the list of articles and a single article

We have the data model, test entries, the application skeleton, and a convenient way to connect to Flotiq. Now let's move on to displaying content. In the example application, we will list Projects and allow displaying the details of a single Project.

Listing projects on the application's homepage

1. Prepare app configuration to display images from Flotiq host. Thanks to that, we can utilize the next/image component.

Update the file nextjs.config.ts to containg the following configuration in the images key:

/** @type {import('next').NextConfig} */
const nextConfig = {
    images: {
        remotePatterns: [
            {
                protocol: 'https',
                hostname: 'api.flotiq.com',
                port: '',
                pathname: '/**',
            },
        ],
    },
};

export default nextConfig;

Note: the change may require rerunning the command yarn dev.

2. Replace the example homepage code defined in _/app/page.ts_x.

import { fetchAllProjects} from "@/lib/api";
import { Project } from "../../flotiqApi/src";
import Image from "next/image";
import Link from "next/link";

export default async function Home() {
  const projects = await fetchAllProjects();

  return (
    <main className="max-w-6xl mx-auto px-4 py-10">
      <h1 className="text-2xl font-bold mb-8 border-b-2 border-gray-600">Our Projects</h1>
      <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
        {
          projects.data?.map((project: Project) => (
            <article key={project.id}>
              <Link href={`/projects/${project.slug}`}>
                <h2 className="text-xl font-semibold mb-2">{project.name}</h2>
                <Image
                  src={`https://api.flotiq.com${project.photos?.[0].url}`}
                  alt={project.name}
                  className="w-full h-auto rounded"
                  width={400}
                  height={300}
                />
              </Link>
            </article>
          ))
        }
      </div>
    </main>
  );
}

Note the following:

  • Line 7: const projects = await fetchAllProjects(); - fetching Projects to display, using the previously prepared API.
  • Line 10: className="max-w-6xl mx-auto px-4 py-10" - using TailwindCSS classes for basic component styling.
  • Line 14: projects.data.map((project: Project) => ( - listing Projects, note that we can use the Project type, which provides attribute suggestions for this object.
  • Line 20: {project.name} - displaying an object's attribute, e.g., the name.

Check how your application looks. Go to http://localhost:3000 and see the results. The homepage should look like this:

Displaying a single Project

As you have probably noticed, the homepage contains a list of projects and a Link component that will lead to the page of a single Project. In this step, we will define routing and display the description of a single Project at the /projects/[slug] address.

1. Add the Tailwind @tailwindcss/typography plugin

The content of one of the fields we want to display - the description field - will be in HTML format, generated by a Rich Text Editor. To correctly handle the HTML tags (e.g., h1, h2, ), we need to extend Tailwind with the @tailwindcss/typography plugin. Otherwise, they will not be styled, as Tailwind relies solely on classes, not HTML tags.

Add the plugin:

yarn add @tailwindcss/typography

Enable the plugin in the tailwind.config.ts file:

// ...other tailwind config

plugins: [
  require('@tailwindcss/typography'),
]

2. Create a single project page /app/projects/[slug]/page.tsx.

According to the Dynamic Route convention in NextJS, the page.tsx file placed in the [slug] directory will be responsible for displaying the content of pages where [slug] will be replaced by possible values from the browser address.

Here is the source code for a single project page:

import { fetchAllProjects, fetchProjectBySlug } from "@/lib/api";
import type { Project, ProjectList } from "../../../../flotiqApi/src";
import Image from "next/image";
import { notFound } from "next/navigation";
import Link from "next/link";

export async function generateStaticParams() {
  const allProjects: ProjectList = await fetchAllProjects();
  return allProjects.data?.map((project: Project) => ({
    slug: project.slug,
  })) || [];
}

interface ProjectProps {
  params: {
    slug: string
  };
}

export default async function Project(props: ProjectProps) {
  const project = await fetchProjectBySlug(props.params.slug);

  if (!project) {
    notFound();
  }

  return (
    <main className="max-w-6xl mx-auto px-4 py-10">
      <h1 className="text-2xl font-bold mb-8 border-b-2 border-gray-600">{project.name}</h1>
      <div className="grid grid-cols-2 gap-6">
        <div>
          <Image
            src={`https://api.flotiq.com${project.photos?.[0].url}`}
            alt={project.name}
            className="w-full h-auto rounded"
            width={400}
            height={300}
          />
        </div>
        <div>
          <div
            dangerouslySetInnerHTML={{__html: project.description ?? ''}}
            className="prose prose-invert"
          />
        </div>
        <Link href="/">Back</Link>
      </div>
    </main>
  );
}

Note the following:

  • Line 7: The generateStaticParams function is responsible for generating all possible paths based on the slug field.
  • Line 21: Using the previously prepared fetchProjectBySlug function to fetch projects from Flotiq.
  • Line 43: Using the classes “prose prose-invert”, i.e., className="prose prose-invert", so that the code returned by Flotiq in the description field (Rich Text type) will be correctly styled.

You just need to navigate to the specific project page, in our case http://localhost:3000/projects/smart-home-automation-system to display the finished page:

5. Building a statically generated application

Currently, we have a page with a list of projects and a detailed project page, both optimized for using React Server Components and static rendering. This provides exceptional application speed; however, its content is updated only during the build process.

Create a production-optimized application by running the command:

yarn build

Next, run the application:

yarn start

Go to ht

Author Of article : Paweł Panowicz Read full article