Astro RSS Feed

XML and JSON feeds

astrorss-feed
Published 2022-04-29

Intro

RSS Feeds are a good way to publish your articles and have others consume them at their convenience. People can subscribe to your feed, along with other feeds, and leverage an RSS program that gives them features such as previews, multi-feed aggregation, tagging, favorites, read/unread, new content, etc.

History

rss feed icon

XML

Seems RSS feeds were standardized circa 1999. They started as XML. According to the wikipedia entry, had wide-spread popularity during the 2000s, lost popularity during the 2010s, and have regained interest again 2018+…

JSON

After XML, came JSON, and with it an alternative RSS Feed jsonfeed.

It is essentially the same.

The code on my astro site

I implemented an XML version, and a JSON version on my site.

I went ahead and used non-HTML pages instead of the recommended (at the time) way using getStaticPaths({rss}).

feedr.js

Because I am doing 2 versions, I encapsulated some things into a helper object rss-feed.js that I import on both versions.

//-- /src/rss-feed.js
const feedr = {
  domain: "https://www.readonlychild.com",
  title: "readonlychild rss feed",
  description: "Random post entries.",
  items: async () => {
    let posts = await import.meta.globEager('./pages/blog/*.md');
    let postAry = [];
    for (let postkey in posts) {
      if (posts[postkey].frontmatter.published && posts[postkey].frontmatter.title) {
        postAry.push(posts[postkey]);
      }
    }
    postAry.sort((a, b) => {
      if (a.frontmatter.published < b.frontmatter.published) return 1;
      return -1;
    });
    return postAry;
  }
};

export default feedr;

Holds domain, title, description, and a function items that uses import.meta.globEager to pick up my md files.

XML

//-- /src/pages/rss-feed.xml.js
import feedr from './../rss-feed.js';

export async function get() {
  let xml = [];

  const domain = feedr.domain;

  xml.push('<?xml version="1.0" encoding="utf-8"?>');
  xml.push('<rss version="2.0">');
  xml.push('<channel>');
  
  xml.push(`<title>${feedr.title}</title>`);
  xml.push(`<link>${domain}/blog/</link>`);
  xml.push(`<description>${feedr.description}</description>`);
  xml.push(`<lastBuildDate>${new Date().toString()}</lastBuildDate>`);
  
  let posts = await feedr.items();
  
  posts.forEach(async (post) => {
    let categories = '';
    post.frontmatter.tags.forEach((tag) => {
      categories += `<category><![CDATA[${tag}]]></category>`;
    });

    xml.push(`<item>
 <title><![CDATA[${post.frontmatter.title}]]></title>
 <link>${domain}${post.url}</link>
 <guid>${domain}${post.url}</guid>
 <description>
  <![CDATA[
   <img src="${post.frontmatter.og.basic.image}" /><br/><br/>
   ${post.frontmatter.summary}
   <br/><br/>[ <a href="${domain}${post.url}">Read full post</a> ]
  ]]>
 </description>
 <pubDate>${post.frontmatter.published}</pubDate>
 ${categories}
</item>`);
  });

  xml.push('</channel>');
  xml.push('</rss>');

  return {
    body: xml.join('')
  };
};

View XML

JSON

import feedr from './../rss-feed.js';

export async function get() {
  let feed = {};

  const domain = feedr.domain;

  feed.version = 'https://jsonfeed.org/version/1.1';
  feed.title = feedr.title;
  feed.home_page_url = `${domain}/blog/`;
  feed.feed_url = `${domain}/rss-feed.json`;
  feed.description = feedr.description;
  //feed.icon = ''; <!-- other props -->
  //feed.favicon = '';
  //feed.authors = [ { name url avatar } ];
  //feed.language = 'en' | 'en-US'

  feed.items = [];
  
  let posts = await feedr.items();
  
  posts.forEach(async (post) => {
    feed.items.push({
      id: `${domain}${post.url}`,
      title: `${post.frontmatter.title}`,
      content_text: post.frontmatter.summary,
      summary: post.frontmatter.summary,
      image: post.frontmatter.og.basic.image,
      date_published: post.frontmatter.published,
      tags: post.frontmatter.tags,
      //language: 'en-US',
      content_html: `<img src="${post.frontmatter.og.basic.image}"/>
 <p>${post.frontmatter.summary}</p>
 <p><a href="${domain}${post.url}">Read full post</a></p>`,
      url: `${domain}${post.url}`
    });

  });

  return {
    body: JSON.stringify(feed,null,2)
  };
};

View JSON

Conclusion

In my case, I chose to provide an image and the summary, along with a link to read the full post.

Most of my posts may include astro components in them and I have not figured out a way to generate the markup with rendered components, to place it in the xml/json.

What next

Seems Ben is working on an rss integration, which I will be checking out once it drops.



Back to Post List
ok!