Go-based REST API for Malaysian running events aggregation platform
Part of the Runners List Platform - a microservices-ready architecture for scraping, storing, and serving running event data across Malaysia.
The Runners List API is the central hub of a three-component platform that aggregates running events across Malaysia. It provides a RESTful API for managing event data, with built-in authentication, validation, and automated data ingestion from web scrapers.
This API is part of a microservices-ready architecture consisting of three core services:
graph LR
A[Python Scraper] -->|POST /internal/sync| B[Go API]
B -->|PostgreSQL| C[(Database)]
D[Next.js Frontend] -->|GET /events| B
E[GitHub Actions] -.->|Daily Cron| A
- Repository: runners-list-scraper
- Purpose: Extracts running event data from Malaysian event listing websites
- Tech: Python, Selenium, BeautifulSoup4
- Features:
- Scrapes event name, date, location, state, distance
- Automated retry logic with exponential backoff
- Sends data to API via secure internal endpoint
- Repository: runners-list-api
- Purpose: Central data hub with RESTful API for event management
- Tech: Go, Fiber v2, GORM, PostgreSQL
- Features:
- Internal sync endpoint for scraper data ingestion
- JWT authentication for protected routes
- API key authentication for scraper
- Upsert logic to prevent duplicate events
- Hexagonal architecture (Ports & Adapters)
- Repository: runners-list-web
- Purpose: User-facing web application for browsing events
- Tech: Next.js 15, React 18, TypeScript, Tailwind CSS, Shadcn UI
- Planned Features:
- Real-time event data from API
- Search and filter by state, distance, date
- ISR (Incremental Static Regeneration)
- Dark mode support
runners-list-api/
├── cmd/ # Application entry points
│ ├── main.go # Main application
│ └── routes.go # Route definitions
├── internal/
│ ├── adapter/ # External adapters
│ │ ├── database/ # Database connection
│ │ ├── http/ # HTTP handlers
│ │ ├── middleware/ # HTTP middleware
│ │ └── repository/ # Data persistence
│ ├── core/ # Business logic
│ │ ├── domain/ # Domain models
│ │ └── service/ # Business services
│ ├── port/ # Interface definitions
│ └── config/ # Configuration
└── pkg/ # Shared utilities
type Events struct {
gorm.Model // ID, CreatedAt, UpdatedAt, DeletedAt
Name string // Event name
Location string // City, State
State string // Malaysian state
Distance string // Race distance (e.g., "21km")
Date time.Time // Event date
Description string // Optional description
RegisterationURL string // Registration link
}- Go 1.23+
- Docker & Docker Compose
- PostgreSQL (or use Docker)
git clone https://github.com/aniqaqill/runners-list-api.git
cd runners-list-apicp .env.example .env
# Edit .env with your configurationRequired Environment Variables:
# Database (Docker)
DB_HOST=db
DB_USER=myrunnerslist
DB_PASSWORD=myrunnerslist
DB_NAME=myrunnerslist
# JWT Secret
JWT_SECRET=your_jwt_secret_key_here
# Internal API Key (for scraper)
INTERNAL_API_KEY=your_internal_api_key_heremake dev-upThe API will be available at http://localhost:8080
# Health check
curl http://localhost:8080/api/v1/
# List events
curl http://localhost:8080/api/v1/events| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/ |
Health check |
GET |
/api/v1/events |
List all events |
POST |
/api/v1/register |
Create user account |
POST |
/api/v1/login |
Get JWT token |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/protected/events/create-events |
Create single event |
DELETE |
/api/v1/protected/events/:id |
Delete event |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/v1/internal/sync |
X-Internal-Token |
Bulk event sync from scraper |
Request:
curl -X POST http://localhost:8080/api/v1/internal/sync \
-H "Content-Type: application/json" \
-H "X-Internal-Token: your_api_key_here" \
-d '{
"events": [
{
"name": "Penang Bridge Run",
"location": "Penang",
"state": "Penang",
"distance": "10km",
"date": "2026-11-15",
"registration_url": "https://example.com"
}
]
}'Response:
{
"success": true,
"inserted": 1,
"updated": 0,
"total": 1
}If you are lazy for every command run :
make help # Show all commandscmd/- Application entry points and route definitionsinternal/adapter/- External adapters (HTTP, database, repositories)internal/core/- Business logic (domain models, services)internal/port/- Interface definitions (ports)pkg/- Shared utilities
# All tests
make test
# Unit tests with coverage
make unit-test
# Verbose output
make test-verbose
# Generate coverage report
make coverageDevelopment:
docker compose -f docker-compose.dev.yml up --buildProduction:
docker compose up --build -d- API Specification: See API Endpoints section
- Write tests for new features
- Update documentation as needed
- Run
make fmtbefore committing - Ensure all tests pass (
make test)
Part of the Runners List Platform | Scraper | API | Frontend