A small Go HTTP service that generates an RSS 2.0 feed from one or more users' LeetCode Solution Articles (Discuss) using LeetCode's GraphQL API.
- RSS feed endpoint:
GET /leetcode.xml - Health endpoint:
GET /health - In-memory TTL cache for the generated RSS
- Optional support for authenticated requests via
LEETCODE_COOKIEandLEETCODE_CSRF - Public per-feed RSS endpoint:
GET /f/:feedID/:secret.xml - Authenticated feed management API (requires Clerk):
GET /me,GET /feeds,POST /feeds,PATCH /feeds/:id,POST /feeds/:id/rotate,DELETE /feeds/:id
The Go module lives under leetcode-rss/:
leetcode-rss/cmd/api/: server entrypoint and routesleetcode-rss/internal/api/: handlers, feed service, cacheleetcode-rss/internal/leetcode/: GraphQL client, query, modelsleetcode-rss/internal/rss/: RSS structs and XML renderingleetcode-rss/internal/store/: database repository layer (SQLite/TursoDB)leetcode-rss/migrations/: database schema migrations (goose)leetcode-rss/data/: local SQLite database filesleetcode-rss/.env.example: example local configuration
- Go version specified in
leetcode-rss/go.mod - Make (optional, for the provided
Makefile) - goose for database migrations (optional for development)
# Install goose for database migrations
go install github.com/pressly/goose/v3/cmd/goose@latestcd leetcode-rss
cp .env.example .env
# edit .env with your settingsmake migrate-upmake runThen visit:
http://localhost:8080/(basic info)http://localhost:8080/healthhttp://localhost:8080/leetcode.xml(RSS)
curl -i http://localhost:8080/health
curl -i http://localhost:8080/leetcode.xmlCreate a local env file at leetcode-rss/.env (see leetcode-rss/.env.example):
# Server configuration
PORT=8080
HANDLER_TIMEOUT=10s
# LeetCode API settings
LEETCODE_USERNAMES=user_one,user_two,user_three
LEETCODE_USERNAME=user_one
LEETCODE_GRAPHQL_ENDPOINT=https://leetcode.com/graphql/
LEETCODE_MAX_ARTICLES=15
LEETCODE_COOKIE=
LEETCODE_CSRF=
# Cache settings
CACHE_TTL=2m
# Database configuration (SQLite for local dev)
DATABASE_URL=file:./data/leetrss.db?_journal=WAL&_timeout=5000
# Public URL for generating feed URLs
PUBLIC_BASE_URL=http://localhost:8080
# Per-feed RSS cache TTL
RSS_CACHE_TTL=5m
# Clerk authentication
CLERK_SECRET_KEY=
# Limits
MAX_FEEDS_PER_USER=3
MAX_USERNAMES_PER_FEED=3| Variable | Default | Description |
|---|---|---|
LEETCODE_USERNAMES |
(required) | Comma-separated list of LeetCode usernames |
PORT |
8080 |
Server listen port |
HANDLER_TIMEOUT |
10s |
Per-request handler timeout (Go duration) |
CACHE_TTL |
2m |
In-memory cache TTL (Go duration) |
LEETCODE_MAX_ARTICLES |
15 |
Max articles per user (clamped 1-50) |
LEETCODE_GRAPHQL_ENDPOINT |
https://leetcode.com/graphql/ |
GraphQL endpoint |
LEETCODE_COOKIE |
(optional) | Cookie header for authenticated requests |
LEETCODE_CSRF |
(optional) | CSRF token for authenticated requests |
DATABASE_URL |
file:./data/leetrss.db?... |
SQLite or TursoDB connection string |
PUBLIC_BASE_URL |
http://localhost:8080 |
Base URL for feed URLs in API responses |
RSS_CACHE_TTL |
5m |
Per-feed cache TTL for multi-tenant feeds |
CLERK_SECRET_KEY |
(optional) | Enables Clerk auth for protected feed endpoints |
MAX_FEEDS_PER_USER |
3 |
Max number of feeds per user (clamped 1-100) |
MAX_USERNAMES_PER_FEED |
3 |
Max usernames per feed (clamped 1-20) |
If CLERK_SECRET_KEY is set, the service enables protected API routes and verifies Clerk JWTs:
GET /me: returns the current user recordGET /feeds: list feeds for the userPOST /feeds: create a new feedPATCH /feeds/:id: update feed settingsPOST /feeds/:id/rotate: rotate the feed secretDELETE /feeds/:id: delete a feed
When the secret key is missing, these routes are not registered.
The service uses SQLite for local development and can use TursoDB for production.
# Run migrations
make migrate-up
# Check migration status
make migrate-status
# Rollback last migration
make migrate-down
# Create a new migration
make migrate-create NAME=add_new_table# Install Turso CLI
curl -sSfL https://get.tur.so/install.sh | bash
# create za database
turso db create leetrss-prod
# get connection URL
turso db show --url leetrss-prod
# create auth token
turso db tokens create leetrss-prod
# Set DATABASE_URL in prod environment
# DATABASE_URL=libsql://name-prod-myorg.turso.io?authToken=eyJ...
# Run migrations with goose turso driver
goose -dir migrations turso "$DATABASE_URL" upcmd/api/main.goloads config from environment (and.envif present).- The service calls LeetCode GraphQL to fetch the most recent solution articles for each configured user (currently
15per user). - Articles from all users are merged and sorted by creation date(most recent first).
- Each article is mapped to an RSS
<item>with:title: article titlelink: solution permalink, e.g.https://leetcode.com/problems/{questionSlug}/solutions/{topicId}/{slug}/guid: stable identifier based on topic and uuidpubDate: article creation time
- The rendered XML is cached for
CACHE_TTL.
Run commands from leetcode-rss/:
make run: start the servermake test: run tests (go test ./... -mod=readonly)make fmt: format withgofmtmake tidy: rungo mod tidymake migrate-up: run database migrationsmake migrate-down: rollback last migrationmake migrate-status: show migration status
- Uses Go’s standard
testingpackage. - Add tests as
*_test.gofiles next to the code underleetcode-rss/internal/....
missing env LEETCODE_USERNAMES: setLEETCODE_USERNAMESin the env orleetcode-rss/.env.leetcode http 4xx/5xxorgraphql error: LeetCode may be rate-limiting, blocking, or returning an error. IncreaseCACHE_TTLand consider settingLEETCODE_COOKIE/LEETCODE_CSRFif your feed requires authentication.- RSS link looks wrong: solution links rely on
questionSlugreturned by the API; if LeetCode changes response fields, the link format may need updating.