Skip to content

Repository files navigation

πŸ“° RSS Aggregator

A lightweight Go service that aggregates RSS/Atom feeds into a PostgreSQL database and exposes a clean REST API to manage users, feeds, subscriptions, and posts.


✨ Key Features

  • πŸ‘€ Create users (server generates an API key)
  • πŸ“‘ Register RSS/Atom feeds and follow/unfollow them
  • πŸ”„ Background scraper that periodically fetches feeds and stores posts
  • πŸš€ Simple RESTful HTTP API with lightweight JSON responses

🧰 Prerequisites

  • Go 1.20+ (module-aware)
  • PostgreSQL database
  • (Optional) sqlc β€” required only if you want to regenerate typed queries

βš™οΈ Configuration

The service reads configuration from environment variables. A local .env file is also loaded automatically if present.

Variable Description
PORT TCP port the HTTP server listens on (required)
DB_URL PostgreSQL connection string (required)

Example:

postgres://user:password@localhost:5432/rss_aggregator?sslmode=disable

πŸ—οΈ Build & Run

1️⃣ Build

go build -o rss_aggregator

2️⃣ Run

PORT=8080 \
DB_URL="postgres://user:pass@localhost:5432/rss_aggregator?sslmode=disable" \
./rss_aggregator
  • The HTTP server starts immediately
  • The background scraper runs every 1 minute using 10 goroutines (configurable in code)

πŸ—„οΈ Database

This project uses sqlc-generated typed queries, located under:

internal/database

If you modify SQL files, regenerate queries using sqlc (see sqlc documentation).

Minimal SQL Schema

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  name TEXT NOT NULL,
  api_key TEXT NOT NULL UNIQUE
);

CREATE TABLE feeds (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  name TEXT NOT NULL,
  url TEXT NOT NULL,
  user_id UUID REFERENCES users(id) ON DELETE CASCADE,
  last_fetched_at TIMESTAMP WITH TIME ZONE
);

CREATE TABLE feed_follows (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  user_id UUID REFERENCES users(id) ON DELETE CASCADE,
  feed_id UUID REFERENCES feeds(id) ON DELETE CASCADE
);

CREATE TABLE posts (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
  title TEXT NOT NULL,
  description TEXT,
  published_at TIMESTAMP WITH TIME ZONE NOT NULL,
  url TEXT NOT NULL UNIQUE,
  feed_id UUID REFERENCES feeds(id) ON DELETE CASCADE
);

πŸ” API Authentication

Some endpoints require an API key passed via the Authorization header:

Authorization: ApiKey <your_api_key>

🌐 API Reference

Base Path: /v1

Health & Debug

Method Endpoint Description
GET /healthz Health/readiness check
GET /error Sample 400 error response

Users

Method Endpoint Auth Description
POST /users ❌ Create a new user
GET /users βœ… Get authenticated user

Feeds

Method Endpoint Auth Description
POST /feeds βœ… Create a feed
GET /feeds ❌ List all feeds

Feed Follows

Method Endpoint Auth Description
POST /feed_follows βœ… Follow a feed
GET /feed_follows βœ… List followed feeds
DELETE /feed_follows/{id} βœ… Unfollow a feed

Posts

Method Endpoint Auth Description
GET /posts βœ… Get latest posts (limit 10)

πŸ“Œ API Usage Examples

Create a User

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"name":"Alice"}' \
  http://localhost:8080/v1/users

Create a Feed (Authenticated)

curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: ApiKey <your_api_key>" \
  -d '{"name":"Golang Blog","url":"https://blog.golang.org/feed.atom"}' \
  http://localhost:8080/v1/feeds

Follow a Feed

curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: ApiKey <your_api_key>" \
  -d '{"feed_id":"<feed-uuid>"}' \
  http://localhost:8080/v1/feed_follows

Get User Posts

curl -X GET \
  -H "Authorization: ApiKey <your_api_key>" \
  http://localhost:8080/v1/posts

πŸ› οΈ Development Notes

  • Background scraper is started via startScraping and fetches feeds concurrently
  • Scraper settings (interval & concurrency) are currently hardcoded in main.go
  • CORS is enabled for all origins (adjust in main.go for production)
  • JSON helpers and error utilities live in json.go
  • Authorization logic is implemented in internal/auth/auth.go

🀝 Contributing

Contributions are welcome!

  1. Open an issue describing the bug or enhancement
  2. Create a feature/topic branch
  3. Submit a pull request

⭐ If you find this project useful, consider giving it a star!

About

A lightweight Go service that aggregates RSS/Atom feeds into a PostgreSQL database and exposes a clean REST API to manage users, feeds, subscriptions, and posts.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages