Creating A Blog RSS/Atom Feed With Next.js Typescript

Creating A Blog RSS/Atom Feed With Next.js Typescript

Learn how to add an RSS feed to your app without installing any additional packages

·

3 min read

RSS feeds are a great way to syndicate your content to readers across various platforms. Setting up an RSS feed using Next.js is similar to setting up a sitemap (see sitemap guide here).

Below I will walk you through how we can set up your RSS feed using Next.js without installing additional npm packages. Our step-by-step guide walks you through what we did to create the Avana Wallet Blog RSS feed.

Step 1: Create the page

Create the endpoint for your RSS feed. The endpoint will serve XML content similar to sitemap.xml.

We chose the endpoint https://www.avanawallet.com/feeds/blog/.

import axios from 'axios';
import { appConfig } from './config';

function BlogFeed() {
  // getServerSideProps will do the heavy lifting
}

export async function getServerSideProps({ res }: { res: any }) {
  const resp = await axios.post(appConfig.apiEndpoint,{data});
  const feed = generateRssFeed(resp.data);

  res.setHeader('Content-Type', 'text/xml');
  res.write(feed);
  res.end();

  return {
    props: {},
  };
}

export default BlogFeed;

Step 2: Add logic to render XML

Our RSS/Atom feed consists of two primary components:

1. Channel information: This is information about the blog (title, description, link, etc)

2. Feed items: These are the blogposts

The code below generates XML using dynamic data from our backend API.

interface BlogPostFeedItem {
  title: string;
  description: string;
  image: string;
  link: string;
  date: string;
}
interface BlogRssData {
  items: BlogPostFeedItem[];
  updated: string; // last build date
}
function generateRssFeed(data: BlogRssData) {
  const items = `
    ${data.items.map((post) => {
      return `<item>
        <title>${post.title}</title>
        <link>${post.link}</link>
        <description>${post.description}</description>
        <pubDate>${post.date}</pubDate>
        <guid>${post.link}</guid>
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/"
          url="${post.image}"
          height="600" width="900" />
      </item>`;
    })}`;
  const channelTitle = 'Avana Wallet Blog';
  const channelLink = 'http://www.avanawallet.com/blog/';
  const channelFeed = 'https://www.avanawallet.com/feeds/blog/';
  const channelDescription =
    'Our topics include general crypto news, Solana blockchain, non-custodial wallets, Web3 apps, DeFi and NFTs.';
  const channelLanguage = 'en-us';
  const channelLogo =
    'https://cdn.avanawallet.com/assets/branding/logo/avana-wallet-dark-rounded.png';
  return `<?xml version="1.0" encoding="UTF-8"?>
    <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
      <channel>
        <title>${channelTitle}</title>
        <link>${channelLink}</link>
        <description>${channelDescription}</description>
        <atom:link href="${channelFeed}" rel="self"/>
        <language>${channelLanguage}</language>
        <lastBuildDate>${data.updated}</lastBuildDate>
        <image>
          <url>${channelLogo}</url>
          <title>${channelTitle}</title>
          <link>${channelLink}</link>
        </image>
        ${items}
      </channel>
    </rss>`;
}

Notes:

  • Our API handles formatting and parsing data. You can move this logic to Next.js if needed. It's important to note that dates should be rendered as a string similar to this format: Sun, 15 May 2022 16:33:33 +0000.
  • We hardcoded certain static items that are normalized and will not change. For instance, the height and width of the blog images. You can make these fields dynamic if needed.
  • Setting up the backend API will vary depending on your database. I recommend returning an object containing the serialized blogpost data (title, description, image, date published) as well as the latest blog post date published.
  • Media references are entirely optional. You can remove the media:thumbnail and image tags if needed.
  • Be careful changing the media tags - RSS feeds are picky and do not allow all tags. For example, the image tag cannot be used with an item.

Step 3: Generating and checking the RSS feed

Next, we need to check the output from the feed to make sure it validates. This is important because there are common standards for parsing RSS/Atom feeds.

Our output looks something like this:

<rss version="2.0">
<channel>
<title>Avana Wallet Blog</title>
<link>http://www.avanawallet.com/blog/</link>
<description>
Our topics include general crypto news, Solana blockchain, non-custodial wallets, Web3 apps, DeFi and NFTs.
</description>
<atom:link href="https://www.avanawallet.com/feeds/blog/" rel="self"/>
<language>en-us</language>
<lastBuildDate>Sun, 15 May 2022 16:33:33 +0000</lastBuildDate>
<image>
<url>
https://cdn.avanawallet.com/assets/branding/logo/avana-wallet-dark-rounded.png
</url>
<title>Avana Wallet Blog</title>
<link>http://www.avanawallet.com/blog/</link>
</image>
<item>
<title>
Understanding Solana Non-Custodial Wallet Concepts And Benefits
</title>
<link>
https://www.avanawallet.com/blog/understanding-solana-non-custodial-wallet-concepts-and-benefits-9ba8712a/
</link>
<description>
Learn what makes non-custodial wallets different from custodial wallets
</description>
<pubDate>Sun, 15 May 2022 16:33:33 +0000</pubDate>
<guid>
https://www.avanawallet.com/blog/understanding-solana-non-custodial-wallet-concepts-and-benefits-9ba8712a/
</guid>
<media:thumbnail url="https://cdn.avanawallet.com/assets/media/blog/posts/9ba8712a/cover-lg.jpg" height="600" width="900"/>
</item>
</channel>
</rss>

Great, it looks like our feed is rendering. Now we can check the format using rssboad.org's validator. This validator will tell you if there are any issues with your feed.

Once you've validated your feed it should be good to distribute. The RSS/Atom format we used above is a common standard accepted by most sites.

Hope this guide was helpful!