Skip to content

[Feature] Add RSS & Atom Feed Endpoints (/feed.xml, /atom.xml) #685

Description

@Gautam7352

Overview

Create stable RSS 2.0 and Atom 1.0 feed endpoints so articles are discoverable by feed readers, search engines, and browser recommendation engines. Feeds should include recent articles with proper metadata for syndication.

Current State

  • Existing feed page at apps/the_monkeys/src/app/feed/layout.tsx (HTML-based, personal Following feed)
  • No machine-readable XML feed endpoints
  • No RSS or Atom feed generation

Requirements

1. Create RSS 2.0 Feed Endpoint (/feed.xml)

Location: apps/the_monkeys/src/app/feed.xml/route.ts or dynamic route

Response:

  • Content-Type: application/rss+xml; charset=utf-8
  • Valid RSS 2.0 structure per W3C spec
  • Latest N articles (configurable, default: 50)
  • Include for each item:
    • \u003ctitle\u003e - Article title
    • \u003clink\u003e - Article URL
    • \u003cguid isPermaLink="false"\u003e - Unique article ID
    • \u003cpubDate\u003e - Published date in RFC 2822 format (e.g., Mon, 06 Sep 2021 00:01:00 +0000)
    • \u003cdescription\u003e - Article summary/excerpt (wrapped in CDATA)
    • \u003cenclosure\u003e - Thumbnail image with MIME type
    • \u003cauthor\u003e - Author email or username
    • \u003ccategory\u003e - Article topics/tags

Example RSS structure:

\u003c?xml version="1.0" encoding="UTF-8"?\u003e
\u003crss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"\u003e
  \u003cchannel\u003e
    \u003ctitle\u003eMonkeys - Quality Blogs\u003c/title\u003e
    \u003clink\u003ehttps://monkeys.com.co\u003c/link\u003e
    \u003cdescription\u003eQuality blogs on technology, business, science, lifestyle \u0026 more\u003c/description\u003e
    \u003clanguage\u003een-us\u003c/language\u003e
    \u003cpubDate\u003eMon, 06 Sep 2021 00:01:00 +0000\u003c/pubDate\u003e
    \u003clastBuildDate\u003eMon, 06 Sep 2021 00:01:00 +0000\u003c/lastBuildDate\u003e
    \u003citem\u003e
      \u003ctitle\u003eArticle Title\u003c/title\u003e
      \u003clink\u003ehttps://monkeys.com.co/blog/article-slug-123\u003c/link\u003e
      \u003cguid isPermaLink="false"\u003e123\u003c/guid\u003e
      \u003cpubDate\u003eMon, 06 Sep 2021 00:01:00 +0000\u003c/pubDate\u003e
      \u003cdescription\u003e\u003c![CDATA[Article summary...]]\u003e\u003c/description\u003e
      \u003cenclosure url="https://image-url.png" length="0" type="image/png" /\u003e
      \u003ccategory\u003eTechnology\u003c/category\u003e
      \u003cauthor\u003eauthor@monkeys.com.co\u003c/author\u003e
    \u003c/item\u003e
  \u003c/channel\u003e
\u003c/rss\u003e

2. Create Atom 1.0 Feed Endpoint (/atom.xml)

Location: apps/the_monkeys/src/app/atom.xml/route.ts or dynamic route

Response:

  • Content-Type: application/atom+xml; charset=utf-8
  • Valid Atom 1.0 structure per RFC 4287
  • Latest N articles (configurable, default: 50)
  • Include for each entry:
    • \u003ctitle\u003e - Article title
    • \u003clink href=""\u003e - Article URL with rel="alternate"
    • \u003cid\u003e - Unique article ID (URN or URL)
    • \u003cpublished\u003e - Published date in ISO 8601 format
    • \u003cupdated\u003e - Last modified date in ISO 8601 format
    • \u003csummary\u003e - Article summary
    • \u003ccontent type="html"\u003e - Optional: full article content
    • \u003clink rel="enclosure"\u003e - Thumbnail image
    • \u003cauthor\u003e - Author name and optional email
    • \u003ccategory term=""\u003e - Article topics/tags

Example Atom structure:

\u003c?xml version="1.0" encoding="utf-8"?\u003e
\u003cfeed xmlns="http://www.w3.org/2005/Atom"\u003e
  \u003ctitle\u003eMonkeys - Quality Blogs\u003c/title\u003e
  \u003clink href="https://monkeys.com.co"/\u003e
  \u003clink href="https://monkeys.com.co/atom.xml" rel="self"/\u003e
  \u003cid\u003eurn:uuid:monkeys-feed\u003c/id\u003e
  \u003cupdated\u003e2021-09-06T00:01:00Z\u003c/updated\u003e
  \u003centry\u003e
    \u003ctitle\u003eArticle Title\u003c/title\u003e
    \u003clink href="https://monkeys.com.co/blog/article-slug-123" rel="alternate"/\u003e
    \u003clink href="https://image-url.png" rel="enclosure" type="image/png"/\u003e
    \u003cid\u003eurn:uuid:123\u003c/id\u003e
    \u003cpublished\u003e2021-09-06T00:01:00Z\u003c/published\u003e
    \u003cupdated\u003e2021-09-06T00:01:00Z\u003c/updated\u003e
    \u003csummary\u003eArticle summary...\u003c/summary\u003e
    \u003cauthor\u003e
      \u003cname\u003eAuthor Name\u003c/name\u003e
    \u003c/author\u003e
    \u003ccategory term="Technology"/\u003e
  \u003c/entry\u003e
\u003c/feed\u003e

Implementation Tasks

1. Create Feed Generation Utility

File: apps/the_monkeys/src/services/blog/feedGenerator.ts

  • generateRSSFeed() - Returns RSS XML string
  • generateAtomFeed() - Returns Atom XML string
  • fetchRecentArticles(limit) - Fetches articles from API
  • escapeXml() - XML entity encoding utility
  • formatRFC2822Date() - Convert to RSS date format
  • formatISO8601Date() - Convert to Atom date format

2. Create Route Handlers

File: apps/the_monkeys/src/app/feed.xml/route.ts

export async function GET() {
  const articles = await fetchRecentArticles(50);
  const xml = generateRSSFeed(articles);
  return new Response(xml, {
    headers: {
      'Content-Type': 'application/rss+xml; charset=utf-8',
      'Cache-Control': 'public, max-age=3600', // Cache for 1 hour
    },
  });
}

File: apps/the_monkeys/src/app/atom.xml/route.ts

export async function GET() {
  const articles = await fetchRecentArticles(50);
  const xml = generateAtomFeed(articles);
  return new Response(xml, {
    headers: {
      'Content-Type': 'application/atom+xml; charset=utf-8',
      'Cache-Control': 'public, max-age=3600',
    },
  });
}

3. Add Feed Discovery Links

Update apps/the_monkeys/src/app/layout.tsx metadata to include feed autodiscovery:

alternates: {
  feed: 'https://monkeys.com.co/feed.xml',  // Add RSS feed link
  type: 'application/rss+xml',
},

4. Handle Special Characters & Encoding

  • Properly escape XML entities (\u003c, \u003e, \u0026, \", ')
  • Handle HTML content in descriptions (use CDATA sections)
  • Ensure valid UTF-8 encoding
  • Handle missing/null fields gracefully

Acceptance Criteria

  • /feed.xml returns valid RSS 2.0 (validate with https://validator.w3.org/feed/)
  • /atom.xml returns valid Atom 1.0 (validate with https://validator.w3.org/feed/)
  • Both endpoints return latest 50 articles by default
  • Articles include: title, link, guid/id, pubDate/published, description, enclosure/image
  • Dates are properly formatted (RFC 2822 for RSS, ISO 8601 for Atom)
  • XML is properly escaped and encoded
  • Feed autodiscovery links are in HTML head
  • Caching headers are set (1 hour cache)
  • Error handling for API failures
  • Unit tests for feed generation functions
  • Manual testing with RSS reader (e.g., Feedly, Apple News, Firefox Reader)

Files to Create

  • apps/the_monkeys/src/services/blog/feedGenerator.ts - Feed generation logic
  • apps/the_monkeys/src/app/feed.xml/route.ts - RSS endpoint
  • apps/the_monkeys/src/app/atom.xml/route.ts - Atom endpoint
  • __tests__/feedGenerator.test.ts - Unit tests

Testing Checklist

  • Test with W3C Feed Validator (RSS)
  • Test with W3C Feed Validator (Atom)
  • Subscribe to feeds with popular readers (Feedly, Inoreader, Apple News)
  • Verify article links work correctly
  • Check image thumbnails load properly
  • Validate XML structure with xmllint
  • Performance test with 50+ articles
  • Test caching headers in browser DevTools

Notes

  • Feeds should be stable and immutable (use article IDs, not timestamps)
  • Consider pagination for large feeds (alternate links to next/previous page)
  • Monitor feed fetch performance (may need caching optimization)

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions