A modern REST API backend for the Finnish Science Fiction Bibliography (SuomiSF) built with Go, Gin, and PostgreSQL. This is a Go rewrite of the original Python/Flask SuomiSF project.
- π Authentication: JWT-based authentication with login, registration, and token refresh
- π REST API: Full CRUD operations for works, people, editions, short stories, and tags
- π Search & Filter: Advanced search capabilities with pagination and sorting
- π Foreign Key Resolution: Automatic resolution of foreign keys to human-readable values
- ποΈ Database: PostgreSQL with proper indexing and relationships
- π Pagination: Efficient pagination for large datasets
- π CORS: Configurable CORS support for frontend integration
- π Authorization: Role-based access control
- π JSON API: All responses use JSON format
gosuomisf/
βββ internal/
β βββ api/ # API route definitions
β βββ auth/ # Authentication middleware
β βββ config/ # Configuration management
β βββ database/ # Database connection and queries
β βββ handlers/ # HTTP request handlers
β βββ models/ # Data models and structures
βββ migrations/ # Database migration scripts
βββ scripts/ # Utility scripts
βββ main.go # Application entry point
βββ docker-compose.yml # Docker setup
- Language: Go 1.22+
- Web Framework: Gin
- Database: PostgreSQL 15+
- Authentication: JWT tokens
- Password Hashing: bcrypt
- Testing: Go testing framework with testify
- Containerization: Docker & Docker Compose
- Go 1.22 or higher
- PostgreSQL 15 or higher
- Docker and Docker Compose (optional)
-
Clone the repository
git clone https://github.com/yourusername/gosuomisf.git cd gosuomisf
-
Start the services
docker-compose up -d
-
The API will be available at
http://localhost:8088
-
Clone and build
git clone https://github.com/yourusername/gosuomisf.git cd gosuomisf go mod download go build
-
Set up environment variables
cp .env.example .env # Edit .env with your database credentials
-
Set up PostgreSQL database
psql -U postgres -c "CREATE DATABASE suomisf;" # Import the sample data psql -U postgres -d suomisf < suomisf.sql
-
Run the application
./gosuomisf
The application uses environment variables for configuration. Create a .env
file:
# Database
DB_HOST=localhost
DB_PORT=5432
DB_USER=mep
DB_PASSWORD=password
DB_NAME=suomisf
# JWT
JWT_SECRET=your-secret-key-here
# Server
PORT=8088
GIN_MODE=debug
POST /api/login
- User loginPOST /api/register
- User registrationPOST /api/refresh
- Refresh access token
GET /api/works
- List works with pagination, search, and filteringGET /api/works/{workId}
- Get specific work with full detailsGET /api/works/{workId}/awards
- Get awards for a specific work
GET /api/people
- List people with pagination and searchGET /api/people/{personId}
- Get specific person details
GET /api/editions
- List editions with pagination and searchGET /api/editions/{editionId}
- Get specific edition details
GET /api/shorts
- List short stories with pagination and searchGET /api/shorts/{shortId}
- Get specific short story details
GET /api/tags
- List tags with pagination and searchGET /api/tags/{tagId}
- Get specific tag details
GET /api/frontpagedata
- Get summary statistics for dashboard
All list endpoints support the following query parameters:
Parameter | Type | Default | Description |
---|---|---|---|
page |
integer | 1 | Page number for pagination |
pageSize |
integer | 20 | Number of items per page |
search |
string | - | Search term for filtering results |
sort |
string | id | Field to sort by (varies by endpoint) |
order |
string | asc | Sort order: "asc" or "desc" |
# Get first page of works
curl "http://localhost:8088/api/works?page=1&pageSize=10"
# Search for works containing "science fiction"
curl "http://localhost:8088/api/works?search=science%20fiction"
# Get works sorted by publication year (descending)
curl "http://localhost:8088/api/works?sort=year&order=desc"
# Get a specific work with foreign key resolution
curl "http://localhost:8088/api/works/1"
One of the key features of this API is automatic foreign key resolution. Instead of returning just numeric IDs, the API resolves foreign keys to human-readable values:
Works Example:
{
"id": 1,
"title": "Example Novel",
"type_id": 1,
"type": "Romaani", // β Resolved from worktype table
"language_id": 1,
"language": "englanti", // β Resolved from language table
"bookseries_id": 215,
"bookseries_name": "Example Series" // β Resolved from bookseries table
}
Tags Example:
{
"id": 453,
"name": "Cyberpunk",
"type_id": 1,
"type": "Alagenre" // β Resolved from tagtype table
}
Run the test suite:
# Run all tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run tests for a specific package
go test ./internal/handlers
For development with live reload:
# Install Air for live reloading
go install github.com/cosmtrek/air@latest
# Run with live reload
air
This application implements several security best practices:
- Distroless base image: Uses
gcr.io/distroless/static-debian12:nonroot
to minimize attack surface - Non-root user: Runs as unprivileged user for enhanced security
- Static binary: Compiled with security flags (
-w -s -extldflags "-static"
) - Multi-stage build: Reduces final image size and removes build dependencies
- JWT tokens: Secure token-based authentication
- Password hashing: Uses bcrypt for secure password storage
- HTTPS ready: Configured for TLS termination at reverse proxy level
- Parameterized queries: All database queries use parameter binding to prevent SQL injection
- Connection pooling: Efficient and secure database connection management
- Environment variables: Sensitive configuration stored in environment variables
The application uses the original SuomiSF database schema with tables for:
- work - Books, novels, collections
- worktype - Types of works (novel, collection, etc.)
- language - Languages
- bookseries - Book series information
- tag - Tags and categories
- tagtype - Types of tags (genre, theme, etc.)
- person - Authors and contributors
- edition - Book editions and publications
- shortstory - Short stories and novellas
- Fork the repository
- Create a 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.
- Original SuomiSF project and database schema
- Finnish Science Fiction & Fantasy community
- Go community for excellent libraries and tools
If you have any questions or issues, please:
- Check the Issues page
- Create a new issue if your problem isn't already reported
- Provide as much detail as possible including error messages and steps to reproduce
Note: This is a Go rewrite of the original Python/Flask SuomiSF project, designed to provide better performance and easier deployment while maintaining full compatibility with the existing database schema.
- Environment: godotenv
βββ main.go # Application entry point
βββ internal/
β βββ api/ # API router and middleware
β βββ auth/ # Authentication and JWT utilities
β βββ config/ # Configuration management
β βββ database/ # Database connection and utilities
β βββ handlers/ # HTTP request handlers
β βββ models/ # Data models and structs
βββ migrations/ # Database migration scripts
βββ .env # Environment variables
βββ go.mod # Go module dependencies
βββ Dockerfile # Docker configuration
βββ docker-compose.yml # Docker Compose setup
βββ Makefile # Build and development commands
βββ openapi.yaml # API specification
- Go 1.22 or later
- MySQL 8.0 or later
- Make (optional, for using Makefile commands)
-
Clone and setup dependencies:
git clone <repository-url> cd gosuomisf make install-deps
-
Set up the database:
# Create database mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS suomisf;" # Run migrations make migrate
-
Configure environment: Update
.env
file with your database connection details and JWT secret. -
Run the application:
make run
The API will be available at http://localhost:5050/api
- Start with Docker Compose:
docker-compose up -d
This will start:
- API server on port 5050
- MySQL database on port 3306
- Adminer (database admin) on port 8081
make build
- Build the applicationmake run
- Build and run the applicationmake dev
- Run with hot reload (requires air)make test
- Run testsmake migrate
- Run database migrationsmake fmt
- Format codemake clean
- Clean build artifacts
make install-dev-tools
Install air for hot reload:
go install github.com/cosmtrek/air@latest
Then run:
make dev
Create a .env
file with the following variables:
# Environment
ENVIRONMENT=development
# Database
DATABASE_URL=root:password@tcp(localhost:3306)/suomisf?parseTime=true
# JWT
JWT_SECRET=your-secret-key-change-in-production
JWT_EXPIRY_HOURS=24
REFRESH_EXPIRY_HOURS=168
# Server
PORT=5050
The application uses the following main tables:
users
- User accounts and authenticationworks
- Literary works (books, novels, etc.)people
- Authors and other personseditions
- Published editions of worksshorts
- Short storiestags
- Classification tagsawards
- Awards for works
The API follows the OpenAPI 3.0 specification defined in openapi.yaml
. Key features:
- Authentication: Bearer token authentication for protected endpoints
- Pagination: Consistent pagination across all list endpoints
- Error Handling: Standardized error responses
- Search: Text search capabilities on relevant fields
- Sorting: Configurable sorting on multiple fields
- Register:
POST /api/register
with username, email, and password - Login:
POST /api/login
with username and password - Receive tokens: Get access token (24h) and refresh token (7 days)
- Use API: Include
Authorization: Bearer <access_token>
header - Refresh: Use
POST /api/refresh
with refresh token when access token expires
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests:
make test
- Format code:
make fmt
- Submit a pull request
This project is licensed under the MIT License.