Creating a JSON feed in 11ty

No modules needed

Published on 2024-02-14 | 2m 24s

Ever since Reddit practically ordered the Apollo app to be shut down, I have been getting way more interested in the decentralized web and understanding why it is important.

One thing about the concept that is still alive and kicking is RSS. Despite multiple people saying it's dead, it is still very much here and you can always follow your favorite feeds. It is something I've been using and I have spent multiple hours on NetNewsWire and Reeder since the shutdown.

But there's a problem with traditional RSS - it is in XML which is not really the most friendly format to work with as a developer. That's why the JSON feed was developed.

I use 11ty for my website and there were no modules for generating JSON feeds. Fortunately, I realized early on it was overkill. The code below is all you need to generate a JSON feed:

const { formatRFC3339 } = require("date-fns");

class JSONFeed {
    data() {
        return {
            permalink: "blog.json",
            eleventyExcludeFromCollections: true,
            metadata: {
                title: "David Lozano",
                description: "Hi! This blog is about my experiences in life",
                language: "en",
                url: "https://davidlozano.me",
                authors: [
                    {
                        name: "David Lozano",
                        url: "https://davidlozano.me",
                    },
                ],
            },
        };
    }

    render(data) {
        const { metadata, permalink, collections } = data;
        const BASE_DATA = {
            version: "https://jsonfeed.org/version/1.1",
            title: metadata.title,
            home_page_url: metadata.url,
            feed_url: metadata.url + "/" + permalink,
            description: metadata.description,
            language: metadata.language,
            authors: metadata.authors.map((author) => {
                return {
                    name: author.name,
                    url: author.url,
                };
            }),
        };

        const sorted_blog = collections.published_blog
            .filter((item) => new Date(item.data.date) <= new Date())
            .sort((a, b) => new Date(b.data.date) - new Date(a.data.date));

        return JSON.stringify({
            ...BASE_DATA,
            items: sorted_blog.slice(0, 5).map((post) => {
                const { url, date, data, content } = post;

                return {
                    id: url,
                    url: metadata.url + url,
                    title: data.title,
                    content_html: content.trim(),
                    date_published: formatRFC3339(date),
                };
            }),
        });
    }
}

module.exports = JSONFeed;

Now, I promised in the title that you will not need any modules - I plan to fulfill that promise: You may even use date.toISOString() instead of installing date-fns. While the JSON feed specification requires RFC 3339 (which is why I use it), you can think of RFC 3339 as an extension of the ISO 8601 standard. There are subtle differences but nothing that should be too difficult for feed readers.

After generating the JSON feed, don't forget to add it to your head:

<link
    rel="alternate"
    type="application/feed+json"
    title="RSS Feed"
    href="https://davidlozano.me/blog.json"
/>

Although the spec says to use application/feed+json, you can also add a application/json MIMEtype as well since there are some RSS readers that might not recognize the said MIMEtype.