Hire a web Developer and Designer to upgrade and boost your online presence with cutting edge Technologies

Wednesday, October 23, 2024

Build A Static RSS Reader To Fight Your Inner FOMO

 RSS is a classic technology that fetches content from websites and feeds it to anyone who subscribes to it with a URL. It’s based on XML, and we can use it to consume the feeds in our own apps. Karin Hendrikse demonstrates how to do exactly that with a static site you can use as your personal RSS reader.

In a fast-paced industry like tech, it can be hard to deal with the fear of missing out on important news. But, as many of us know, there’s an absolutely huge amount of information coming in daily, and finding the right time and balance to keep up can be difficult, if not stressful. A classic piece of technology like an RSS feed is a delightful way of taking back ownership of our own time. In this article, we will create a static Really Simple Syndication (RSS) reader that will bring you the latest curated news only once (yes: once) a day.

We’ll obviously work with RSS technology in the process, but we’re also going to combine it with some things that maybe you haven’t tried before, including Astro (the static site framework), TypeScript (for JavaScript goodies), a package called rss-parser (for connecting things together), as well as scheduled functions and build hooks provided by Netlify (although there are other services that do this).

I chose these technologies purely because I really, really enjoy them! There may be other solutions out there that are more performant, come with more features, or are simply more comfortable to you — and in those cases, I encourage you to swap in whatever you’d like. The most important thing is getting the end result!

The Plan

Here’s how this will go. Astro generates the website. I made the intentional decision to use a static site because I want the different RSS feeds to be fetched only once during build time, and that’s something we can control each time the site is “rebuilt” and redeployed with updates. That’s where Netlify’s scheduled functions come into play, as they let us trigger rebuilds automatically at specific times. There is no need to manually check for updates and deploy them! Cron jobs can just as readily do this if you prefer a server-side solution.

During the triggered rebuild, we’ll let the rss-parser package do exactly what it says it does: parse a list of RSS feeds that are contained in an array. The package also allows us to set a filter for the fetched results so that we only get ones from the past day, week, and so on. Personally, I only render the news from the last seven days to prevent content overload. We’ll get there!

But first…

What Is RSS?

RSS is a web feed technology that you can feed into a reader or news aggregator. Because RSS is standardized, you know what to expect when it comes to the feed’s format. That means we have a ton of fun possibilities when it comes to handling the data that the feed provides. Most news websites have their own RSS feed that you can subscribe to (this is Smashing Magazine’s RSS feed: https://www.smashingmagazine.com/feed/). An RSS feed is capable of updating every time a site publishes new content, which means it can be a quick source of the latest news, but we can tailor that frequency as well.

RSS feeds are written in an Extensible Markup Language (XML) format and have specific elements that can be used within it. Instead of focusing too much on the technicalities here, I’ll give you a link to the RSS specification. Don’t worry; that page should be scannable enough for you to find the most pertinent information you need, like the kinds of elements that are supported and what they represent. For this tutorial, we’re only using the following elements: <title>, <link>, <description>, <item>, and <pubDate>. We’ll also let our RSS parser package do some of the work for us.

Creating The State Site

We’ll start by creating our Astro site! In your terminal run pnpm create astro@latest. You can use any package manager you want — I’m simply trying out pnpm for myself.

After running the command, Astro’s chat-based helper, Houston, walks through some setup questions to get things started.

 astro   Launch sequence initiated.

   dir   Where should we create your new project?
         ./rss-buddy

  tmpl   How would you like to start your new project?
         Include sample files

    ts   Do you plan to write TypeScript?
         Yes

   use   How strict should TypeScript be?
         Strict

  deps   Install dependencies?
         Yes

   git   Initialize a new git repository?
         Yes

I like to use Astro’s sample files so I can get started quickly, but we’re going to clean them up a bit in the process. Let’s clean up the src/pages/index.astro file by removing everything inside of the <main></main> tags. Then we’re good to go!

From there, we can spin things by running pnpm start. Your terminal will tell you which localhost address you can find your site at.

Pulling Information From RSS feeds

The src/pages/index.astro file is where we will make an array of RSS feeds we want to follow. We will be using Astro’s template syntax, so between the two code fences (—), create an array of feedSources and add some feeds. If you need inspiration, you can copy this:

const feedSources = [
  'https://www.smashingmagazine.com/feed/',
  'https://developer.mozilla.org/en-US/blog/rss.xml',
  // etc.
]

Now we’ll install the rss-parser package in our project by running pnpm install rss-parser. This package is a small library that turns the XML that we get from fetching an RSS feed into JavaScript objects. This makes it easy for us to read our RSS feeds and manipulate the data any way we want.

Once the package is installed, open the src/pages/index.astro file, and at the top, we’ll import the rss-parser and instantiate the Partner class.

import Parser from 'rss-parser';
const parser = new Parser();

We use this parser to read our RSS feeds and (surprise!) parse them to JavaScript. We’re going to be dealing with a list of promises here. Normally, I would probably use Promise.all(), but the thing is, this is supposed to be a complicated experience. If one of the feeds doesn’t work for some reason, I’d prefer to simply ignore it.

Why? Well, because Promise.all() rejects everything even if only one of its promises is rejected. That might mean that if one feed doesn’t behave the way I’d expect it to, my entire page would be blank when I grab my hot beverage to read the news in the morning. I do not want to start my day confronted by an error.

Instead, I’ll opt to use Promise.allSettled(). This method will actually let all promises complete even if one of them fails. In our case, this means any feed that errors will just be ignored, which is perfect.

Let’s add this to the src/pages/index.astro file:

interface FeedItem {
  feed?: string;
  title?: string;
  link?: string;
  date?: Date;
}

const feedItems: FeedItem[] = [];

await Promise.allSettled(
  feedSources.map(async (source) => {
    try {
      const feed = await parser.parseURL(source);
      feed.items.forEach((item) => {
        const date = item.pubDate ? new Date(item.pubDate) : undefined;
        
          feedItems.push({
            feed: feed.title,
            title: item.title,
            link: item.link,
            date,
          });
      });
    } catch (error) {
      console.error(`Error fetching feed from ${source}:`, error);
    }
  })
);

This creates an array (or more) named feedItems. For each URL in the feedSources array we created earlier, the rss-parser retrieves the items and, yes, parses them into JavaScript. Then, we return whatever data we want! We’ll keep it simple for now and only return the following:

  • The feed title,
  • The title of the feed item,
  • The link to the item,
  • And the item’s published date.

The next step is to ensure that all items are sorted by date so we’ll truly get the “latest” news. Add this small piece of code to our work:

const sortedFeedItems = feedItems.sort((a, b) => (b.date ?? new Date()).getTime() - (a.date ?? new Date()).getTime());

Oh, and… remember when I said I didn’t want this RSS reader to render anything older than seven days? Let’s tackle that right now since we’re already in this code.

We’ll make a new variable called sevenDaysAgo and assign it a date. We’ll then set that date to seven days ago and use that logic before we add a new item to our feedItems array.

This is what the src/pages/index.astro file should now look like at this point:

---
import Layout from '../layouts/Layout.astro';
import Parser from 'rss-parser';
const parser = new Parser();

const sevenDaysAgo = new Date();
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);

const feedSources = [
  'https://www.smashingmagazine.com/feed/',
  'https://developer.mozilla.org/en-US/blog/rss.xml',
]

interface FeedItem {
  feed?: string;
  title?: string;
  link?: string;
  date?: Date;
}

const feedItems: FeedItem[] = [];

await Promise.allSettled(
  feedSources.map(async (source) => {
    try {
      const feed = await parser.parseURL(source);
      feed.items.forEach((item) => {
        const date = item.pubDate ? new Date(item.pubDate) : undefined;
        if (date && date >= sevenDaysAgo) {
          feedItems.push({
            feed: feed.title,
            title: item.title,
            link: item.link,
            date,
          });
        }
      });
    } catch (error) {
      console.error(`Error fetching feed from ${source}:`, error);
    }
  })
);

const sortedFeedItems = feedItems.sort((a, b) => (b.date ?? new Date()).getTime() - (a.date ?? new Date()).getTime());

---

<Layout title="Welcome to Astro.">
  <main>
  </main>
</Layout>

Rendering XML Data

It’s time to show our news articles on the Astro site! To keep this simple, we’ll format the items in an unordered list rather than some other fancy layout.

All we need to do is update the <Layout> element in the file with the XML objects sprinkled in for a feed item’s title, URL, and publish date.

<Layout title="Welcome to Astro.">
  <main>
  {sortedFeedItems.map(item => (
    <ul>
      <li>
        <a href={item.link}>{item.title}</a>
        <p>{item.feed}</p>
        <p>{item.date}</p>
      </li>
    </ul>
  ))}
  </main>
</Layout>

Go ahead and run pnpm start from the terminal. The page should display an unordered list of feed items. Of course, everything is styled at the moment, but luckily for you, you can make it look exactly like you want with CSS!

And remember that there are even more fields available in the XML for each item if you want to display more information. If you run the following snippet in your DevTools console, you’ll see all of the fields you have at your disposal:

feed.items.forEach(item => {}

Scheduling Daily Static Site Builds

We’re nearly done! The feeds are being fetched, and they are returning data back to us in JavaScript for use in our Astro page template. Since feeds are updated whenever new content is published, we need a way to fetch the latest items from it.

We want to avoid doing any of this manually. So, let’s set this site on Netlify to gain access to their scheduled functions that trigger a rebuild and their build hooks that do the building. Again, other services do this, and you’re welcome to roll this work with another provider — I’m just partial to Netlify since I work there. In any case, you can follow Netlify’s documentation for setting up a new site.

Once your site is hosted and live, you are ready to schedule your rebuilds. A build hook gives you a URL to use to trigger the new build, looking something like this:

https://api.netlify.com/build_hooks/your-build-hook-id

Let’s trigger builds every day at midnight. We’ll use Netlify’s scheduled functions. That’s really why I’m using Netlify to host this in the first place. Having them at the ready via the host greatly simplifies things since there’s no server work or complicated configurations to get this going. Set it and forget it!

We’ll install @netlify/functions (instructions) to the project and then create the following file in the project’s root directory: netlify/functions/deploy.ts.

This is what we want to add to that file:

// netlify/functions/deploy.ts

import type { Config } from '@netlify/functions';

const BUILD_HOOK =
  'https://api.netlify.com/build_hooks/your-build-hook-id'; // replace me!

export default async (req: Request) => {
  await fetch(BUILD_HOOK, {
    method: 'POST',
  })
};

export const config: Config = {
  schedule: '0 0 * * *',
};
If you commit your code and push it, your site should re-deploy automatically. From that point on, it follows a schedule that rebuilds the site every day at midnight, ready for you to take your morning brew and catch up on everything that you think is important.

The Timeless Power Of Spreadsheets

 In this age of endless newfangled organizational tools, the spreadsheet holds firm. Frederick O’Brien explains how, from engineering to design, they can still provide a rock-solid foundation for your work.

Part of me can’t believe I’m writing this article. Applying the insights of Leonardo da Vinci or Saul Bass to web design is more my groove, but sometimes you simply have to write about spreadsheets. You have to advocate for them. Because someone should.

In a checkered career spanning copywriting, journalism, engineering, and teaching, I’ve seen time and time again how powerful and useful spreadsheets are in all walks of life. The cold, hard truth is that you — yes, you — likely have an enormous amount to gain by understanding how spreadsheets work. And, more importantly, how they can work for you.

That’s what this piece is about. It’s a rallying cry, with examples of spreadsheets’ myriad uses and how they can actually, in the right circumstances, be the bedrock of altogether inspiring, lovely things.

Cellular Organisms 

Spreadsheets have been around for thousands of years. Papyrus remnants have been discovered from as far back as 4,600 BC. Their going digital in the late ‘70s was a major factor in the rise of personal computing. Much is (rightly) made of the cultural transformation brought about by the printing press. The digital spreadsheet, not so much.

For as long as people have had projects and data to organize, spreadsheets have been indispensable. They were the original databases.

Spreadsheets don’t always get a lot of attention these days. For organization and workflow, we usually find ourselves in the worlds of Trello, Jira, or GitHub Projects. Datasets live in Oracle, MongoDB, and the like. There are good reasons for these services emerging — everything has its place — but

I do get the sense that specialized tooling causes us to skip over the flexibility and power that today’s spreadsheet editors provide.

This is especially true for smaller projects and ones in their early stages. Yes, sometimes only a huge database will do, but often spreadsheets are more than fit for purpose.

Benefits

What makes spreadsheets so great? We’ll get into a few real-world examples in a second, but several qualities hold true. They include the following:

  • Collaboration
    Cloud-based editors like Google Sheets give groups of people a space in which to collaborate on data. They can serve as a middle ground for people working on different parts of the same project.
  • Structure
    It’s inherent to spreadsheets that they’ll get you thinking about the ‘shape’ of the information you’re dealing with. In the same way that a blank piece of paper invites fluidity of thought, tables coax out frameworks — and both have their place
  • Flexibility
    Spreadsheets can evolve in real time, which is especially useful during the formative stages of a project when the shape of the ‘data’ is still being established. Adding a field is as simple as naming a column, and the ability to weave in formulas makes it easy to infer other values from the ones you have. With stuff like the Google Sheets API, you can even scrape data directly from the spreadsheet
  • Power
    You’d be surprised how much you can do in spreadsheets. Sometimes, you don’t even need bespoke dashboards; you can do it all in the editor. From data visualization to pivot tables, spreadsheet editors come with a bunch of powerful out-of-the-box features.
  • They translate into other data formats
    Spreadsheets are one small jump from the mighty CSV. When the time is right, spreadsheets can still become raw data if you want them to.

Such is the flexibility and power of spreadsheets, and what’s listed here is scratching the surface. Their fundamental strength of organizing data has made them useful for thousands of years, while contemporary enhancements have taken them to the next level.

Case Studies

Below are a few examples from my own experiences that showcase these benefits in the real world. They’re obviously slanted towards my interests, but hopefully, they illustrate the usefulness of spreadsheets in different contexts.

Galaxies (Of The Guardian)

I work as a software engineer at Guardian News & Media, a place where 10% of the time, i.e., one work day every two weeks, is yours to spend on independent learning, side projects, and so on, is part of the working culture. An ongoing project of mine has been Galaxies (of the Guardian), a D3-powered org chart that represents departments as a series of interrelated people, teams, and streams.

What you see above is powered by information stored and edited in spreadsheets. A lambda scraps departmental information using the aforementioned Google Sheets API, then reformats into a shape Galaxies plays nicely with.

This approach has had several benefits. The earliest iterations of Galaxies were only possible because there was already a spreadsheet being maintained by those who needed to keep track of who worked where. Techies and non-techies alike are able to update information easily, and it is transparent to anyone who works inside the organization.

For anyone interested, I wrote a piece about how Galaxies works on the Guardian engineering blog. Suffice it to say here, spreadsheets were — and remain — the engine of the whole thing.

Food Bank Britain #

My background is in journalism, and I still freelance in my own time. As my coding skills have improved, I’ve naturally gravitated towards data journalism, even teaching it for a year at my old journalism school.

Spreadsheets are inseparable from a lot of modern journalism — and, indeed, copyrighting in general. The digital world is awash with data, and good luck making sense of it without a working knowledge of spreadsheets.

For example, a piece I wrote for the Byline Times about foodbanks earlier this year simply wouldn’t have been possible without spreadsheets. It was by collating data from the Trussell Trust, the Independent Food Aid Network, and national census reports that I was able to map out the sheer scale of the UK’s food bank network.

A screenshot of the spreadsheet with the UK’s food banks
(Large preview)
A map with food banks location
(Large preview)

Granted, the map is more visually engaging. But then that’s the idea. It’s the same information, just presented more pointedly.

There are plenty of other instances of spreadsheets being instrumental at the Guardian alone. Typerighter, the newspaper’s automated house style checker, began life as a subeditor’s spreadsheet. User research and bug tracking for the new Feast cooking app, which I worked on during its formative stages, was tracked and discussed in spreadsheets.

And, of course, countless pieces of quality journalism at the Guardian and beyond continue to be powered by them.

Another Cell In The Table

If this piece has got you to at least consider learning more about spreadsheets and spreadsheet editors, you’re in luck. There are countless free learning resources available on the web. Here are a few excellent beginner videos to help you on your way:

As for spreadsheet editors, the big three these days are probably Google Sheets, Microsoft Excel, and LibreOffice Calc (for the open source devotees out there). They all work much the same way. And as you get comfortable with their functionality, new avenues will open.

Data is the lifeblood of the modern web, and spreadsheets remain one of the most accessible, flexible ways to organize, analyze, and share it. As I hope the examples I’ve shared with you show, spreadsheets aren’t inherently boring. They can be, but when used in the right ways, they become the engines of dynamic, impactful work.

The way they go is up to you.