Integrating NeetoPublish with Next.js

NeetoPublish makes it easy to connect and display blog posts in a Next.js application. We can choose to display content using Static Site Generation (SSG) or Server-Side Rendering (SSR) based on how dynamic we want our blog to be.

For detailed API documentation, refer to the NeetoPublish API docs to explore available endpoints and understand how to fetch your blog posts.

Integration options

We have two primary ways to integrate NeetoPublish with Next.js app:

  1. Static Site Generation (SSG)
    Best for performance when the content changes infrequently.

  2. Server-Side Rendering (SSR)
    Ideal when content changes frequently and needs to always be fresh.

1. Static Site Generation (SSG)

In this approach, we fetch blog content at build time and cache it. This improves the performance and speed of the site. When new content is published, we can use webhooks to trigger a revalidation and ensure the content is up-to-date.

Step 1: Fetch data during build

In Next.js, we use getStaticProps to fetch data at build time. This allows us to pre-render the page with the data fetched from the API, improving performance by serving cached content.

Example: Fetching all blog posts

Here’s how we can use getStaticProps to fetch all blog posts from NeetoPublish’s API:

export async function getStaticProps() {
  // Fetching all blog posts from NeetoPublish API
  const res = await fetch('https://{workspace}.neetopublish.com/api/v1/blog_posts', {
    headers: {
      "X-Api-Key": process.env.NEETOPUBLISH_API_KEY, // Add your NeetoPublish API Key
    },
  });

  // Parsing the JSON response to get the posts data
  const posts = await res.json();

  // Returning the posts data as props to the component
  return {
    props: {
      posts, // The posts will be available in the BlogPage component
    },
  };
}               

Step 2: Set up webhooks in NeetoPublish

To ensure our blog posts are always up-to-date, we can set up webhooks to trigger revalidation whenever new content is published in NeetoPublish.

  • In the NeetoPublish Admin panel, navigate to the webhooks section.

  • Add the URL of revalidation endpoint in Next.js. For example:
    https://{yourdomain}.com/api/revalidate.

  • NeetoPublish will generate a secret Key. We copy this key and set it up as an environment variable in the Next.js project. This ensures only requests from NeetoPublish can trigger revalidation.

Step 3: Add a revalidation endpoint

Next.js supports On-Demand Revalidation, which lets us manually refresh specific pages after content updates. For example, we may want to refresh the blog listing page whenever a new post is published.

To achieve this, we create a revalidation endpoint at /api/revalidate. We also add a verifySignature function to ensure that only authorized requests from NeetoPublish can trigger the revalidation. This function generates a hash from the request payload using the webhook secret and compares it with the signature sent in the request header using crypto.timingSafeEqual. This prevents unauthorized or tampered requests from triggering revalidation.

Inside the handler, we call res.revalidate("/blog") to refresh the blog listing page and ensure it always shows the latest content.

import crypto from "crypto";

const escapeHtmlEntities = str => {
  str = str
    .replace(/>/g, "\\u003e")
    .replace(/</g, "\\u003c")
    .replace(/&/g, "\\u0026")
    .replace(/\u2028/g, "\\u2028")
    .replace(/\u2029/g, "\\u2029");

  return str;
};

// Function to verify the webhook signature
const verifySignature = req => {
  if (!req.headers["x-neeto-webhook-signature"]) return false;

  const hmac = crypto.createHmac("sha256", process.env.NEETO_PUBLISH_WEBHOOK_KEY);
  const signature = `sha256=${hmac
    .update(escapeHtmlEntities(JSON.stringify(req.body)))
    .digest("hex")}`;

  const isValid = crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(req.headers["x-neeto-webhook-signature"])
  );

  return isValid;
};

export default async function handler(req, res) {
  const secret = req.headers['x-webhook-secret'];

  // Verify the webhook signature to ensure the request is from NeetoPublish
  if (!verifySignature(req)) {
    return res.status(401).json({ error: "Unauthorized!" });
  }

  try {
    // Revalidate the blog page or use dynamic logic to revalidate specific paths
    await res.revalidate('/blog');
    return res.json({ revalidated: true });
  } catch (err) {
    return res.status(500).json({ message: 'Error revalidating' });
  }
}

2. Server-Side Rendering (SSR)

With Server-Side Rendering, we use getServerSideProps to fetch blog content on every request. This ensures users always see the most recent content without needing to configure webhooks or revalidation. It's a good fit when the content changes frequently and doesn't need to be cached at build time.

Example: Fetching all blog posts

Here’s how we can use getServerSideProps to fetch all blog posts from NeetoPublish’s API:

export async function getServerSideProps() {
  // Fetching all blog posts from NeetoPublish API
  const res = await fetch('https://{workspace}.neetopublish.com/api/v1/blog_posts', {
    headers: {
      "X-Api-Key": process.env.NEETOPUBLISH_API_KEY, // Add your NeetoPublish API Key
    },
  });

  // Parsing the JSON response to get the posts data
  const posts = await res.json();

  // Returning the posts data as props to the component
  return {
    props: {
      posts, // The posts will be available in the BlogPage component
    },
  };
}