A lightweight, efficient RSS feed client for Go that provides a simple interface for fetching and parsing RSS feeds with configurable HTTP client options.
- ✅ Simple, clean API
- ✅ Configurable HTTP client (timeouts, custom clients)
- ✅ Comprehensive error handling
- ✅ Zero external dependencies (uses only Go standard library)
- ✅ Well-tested with extensive test coverage
- ✅ Thread-safe operations
go get -u github.com/junkd0g/karoopackage main
import (
"fmt"
"log"
rss "github.com/junkd0g/karoo"
)
func main() {
client := rss.NewClient()
feed, err := client.GetFeed("https://news.google.com/rss")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Feed Title: %s\n", feed.Channel.Title)
fmt.Printf("Feed Description: %s\n", feed.Channel.Description)
fmt.Printf("Number of items: %d\n", len(feed.Channel.Items))
for _, item := range feed.Channel.Items {
fmt.Printf("- %s: %s\n", item.Title, item.Link)
}
}client := rss.NewClient(rss.WithTimeout(30 * time.Second))httpClient := &http.Client{
Timeout: 15 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
},
}
client := rss.NewClient(rss.WithHTTPClient(httpClient))client := rss.NewClient(
rss.WithTimeout(20 * time.Second),
rss.WithHTTPClient(customHTTPClient),
)feed, err := client.GetFeed("https://example.com/feed.xml")
if err != nil {
switch {
case strings.Contains(err.Error(), "failed to fetch RSS feed"):
// Handle HTTP errors (404, 500, etc.)
log.Printf("HTTP error: %v", err)
case strings.Contains(err.Error(), "Client.Timeout"):
// Handle timeout errors
log.Printf("Request timeout: %v", err)
default:
// Handle other errors (network, XML parsing, etc.)
log.Printf("Error fetching feed: %v", err)
}
return
}type RSS struct {
XMLName xml.Name `xml:"rss"`
Version string `xml:"version,attr"`
Channel struct {
Title string `xml:"title"`
Link string `xml:"link"`
Description string `xml:"description"`
Items []struct {
Title string `xml:"title"`
Link string `xml:"link"`
Description string `xml:"description"`
} `xml:"item"`
} `xml:"channel"`
}type Client struct {
// contains filtered or unexported fields
}func NewClient(opts ...ClientOption) *ClientCreates a new RSS client with optional configuration. Default timeout is 10 seconds.
func WithTimeout(timeout time.Duration) ClientOptionSets a custom timeout for HTTP requests.
func WithHTTPClient(httpClient *http.Client) ClientOptionSets a custom HTTP client for RSS requests.
func (c *Client) GetFeed(url string) (RSS, error)Fetches and parses an RSS feed from the specified URL. Returns the parsed RSS struct or an error.
package main
import (
"fmt"
"log"
rss "github.com/junkd0g/karoo"
)
func main() {
client := rss.NewClient()
feeds := []string{
"https://rss.cnn.com/rss/edition.rss",
"https://feeds.bbci.co.uk/news/rss.xml",
"https://rss.nytimes.com/services/xml/rss/nyt/World.xml",
}
for _, feedURL := range feeds {
feed, err := client.GetFeed(feedURL)
if err != nil {
log.Printf("Error fetching %s: %v", feedURL, err)
continue
}
fmt.Printf("\n=== %s ===\n", feed.Channel.Title)
for i, item := range feed.Channel.Items {
if i >= 3 { // Show only first 3 items
break
}
fmt.Printf("%d. %s\n", i+1, item.Title)
}
}
}package main
import (
"fmt"
"log"
"sync"
"time"
rss "github.com/junkd0g/karoo"
)
func main() {
client := rss.NewClient(rss.WithTimeout(5 * time.Second))
feeds := []string{
"https://rss.cnn.com/rss/edition.rss",
"https://feeds.bbci.co.uk/news/rss.xml",
"https://rss.nytimes.com/services/xml/rss/nyt/World.xml",
}
var wg sync.WaitGroup
results := make(chan string, len(feeds))
for _, feedURL := range feeds {
wg.Add(1)
go func(url string) {
defer wg.Done()
feed, err := client.GetFeed(url)
if err != nil {
results <- fmt.Sprintf("Error fetching %s: %v", url, err)
return
}
results <- fmt.Sprintf("%s: %d items", feed.Channel.Title, len(feed.Channel.Items))
}(feedURL)
}
wg.Wait()
close(results)
for result := range results {
fmt.Println(result)
}
}Run the test suite:
go test -vRun tests with coverage:
go test -v -cover- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Iordanis Paschalidis - junkd0g