How to Build an RSS Feed with F# and Falco
Date: 2025-04-23 | craft | create | falco | fsharp | hamy-xyz | iamhamy | tech |
I recently added an RSS feed to my blog so people with RSS readers can get updates easier.
In this post we'll walk through creating an RSS feed using F# and serving it with Falco.
What is an RSS Feed?
An RSS feed (Really Simple Syndication) is a way to get updates from a source. Typically it's provided by content sources so that consumers can more easily determine if new content exists and where to find it.
It's typically an XML format that contains:
- Info about the source - title, description, url
- List of updates from the source - often new content like posts or podcasts with title, description, url
This provides a simple way for consumers to "subscribe" to an RSS feed so that they can fetch the latest updates.
Example RSS feeds:
F# + Falco Markdown Blog
We'll be building the RSS feed onto a markdown blog served with F# + Falco:
- Web Server: F# + Falco
- Markdown to HTML: Markdig and YamlDotnet
In this post we'll be focused on the RSS feed portion so won't go into detail about how the markdown blog itself is built. For more details, see my previous post: Build a Simple Markdown Blog with F# and Falco.
Note that this is exactly how my current blog is built and mirrors its RSS feed.
We'll be going over the relevant code here but HAMINIONs members get access to the full project source code (GitHub) as well as code from dozens of other example projects we build here.
Building an RSS Feed with F#
We have two primary data types:
RssItem
- A single item in the feedRssChannel
- Represents the feed itself (and containsRssItem
s)
Code: PostPresentation.RssFeed
(GitHub)
module RssFeed =
open System.Xml.Linq
type RssItem = {
Title : string
Link : string
Description : string
PubDate : DateTime
}
type RssChannel = {
Title : string
Link : string
Description : string
Language : string
LastBuildDate : DateTime
Items : RssItem list
}
let rssItemToXml (item : RssItem) =
XElement(XName.Get("item"),
XElement(XName.Get("title"), item.Title),
XElement(XName.Get("link"), item.Link),
XElement(XName.Get("description"), item.Description),
XElement(XName.Get("pubDate"), item.PubDate.ToString("r")),
XElement(XName.Get("guid"),
item.Link)
)
let rssToXml (channel : RssChannel) =
let rss =
XElement(XName.Get("rss"),
XAttribute(XName.Get("version"), "2.0"),
XElement(XName.Get("channel"),
XElement(XName.Get("title"), channel.Title),
XElement(XName.Get("link"), channel.Link),
XElement(XName.Get("description"), channel.Description),
XElement(XName.Get("language"), channel.Language),
XElement(XName.Get("lastBuildDate"), channel.LastBuildDate.ToString("r"))
)
)
// Add all items to the channel
let channelElement = rss.Element(XName.Get("channel"))
channel.Items
|> List.map rssItemToXml
|> List.iter (fun item -> channelElement.Add(item))
// Return the complete RSS document
XDocument (rss)
let rss_channel (serviceTree: PostServiceTree) =
let post_list =
serviceTree
.PostService()
.GetOrderedPosts
0
25
let rss_list =
post_list.Posts
|> List.filter (fun p ->
(p.Date.ToDateTime(TimeOnly(0, 0, 0)) < DateTime.UtcNow))
|> List.map (fun p ->
{
Title = p.Title
Link = $"https://hamy.xyz/blog/{p.Id}"
Description = p.Title
PubDate = (p.Date.ToDateTime(TimeOnly(0, 0, 0)))
})
{
Title = "HAMY LABS"
Link = "https://hamy.xyz/blog"
Description = "Technomancer building Simple Scalable Systems."
Language = "en-us"
LastBuildDate = DateTime.UtcNow
Items = rss_list
}
let handle_rss_feed
(serviceTree : PostServiceTree)
: HttpHandler =
let rss_channel_data = rss_channel serviceTree
fun ctx ->
let feed = rss_channel_data |> rssToXml
let xmlContent = feed.ToString()
ctx
|> Response.withContentType "text/xml; charset=utf-8"
|> Response.ofString (System.Text.Encoding.UTF8) xmlContent
handle_rss_feed
- Entrypoint that gets the channel data, converts it to xml then string, and finally returns it with content typetext/xml
rss_channel
- Helper to build the RSS Channel datarssToXml
- Given an RssChannel, turn that into XMLrssItemToXml
- Creates XML for a given item
The last thing we need to do is configure our route at /blog/rss
:
get "/blog/rss" (
RssFeed.handle_rss_feed blogServiceTree
)
Next
So that's how I built an RSS Feed for my F# + Falco markdown blog.
As a reminder: HAMINIONs get access to the full project source code (GitHub).
If you're curious how I build fullstack webapps with F# + Falco, checkout CloudSeed my F# project boilerplate.
If you liked this post you might also like:
Want more like this?
The best way to support my work is to like / comment / share for the algorithm and subscribe for future updates.