π GoREST is a Go library for building type-safe REST APIs in Go from your existing database schema or from scratch.
- π Codegen REST endpoints, resource DTOs and models for each table
- π Auto-discovery of tables, relations, columns & types
- β‘ Type-safe generic CRUD operations with hooks system
- π Full DTO support with field-level control (
dtotags) - π JWT authentication with context-aware plugins
- π Hook layer to add your business logic and override any API layer
- π§© Modular plugin system that can add features, override some or all existing endpoints or even CLI commands
- β Security best practices, rate limiting, CORS and many more configurable core middleware
- π JSON-LD support with semantic web context (@context, @type, @id)
- π Advanced resource deserialization with IRI and optional on demand relations
- π Advanced serialization, filtering & ordering
- π Page based pagination with Hydra collections
- π¨π»βπ» DAL, migrations and fixtures with PostgreSQL, MySQL and SQLite engines support
- π‘οΈ Production grade errors and processes management
- π³ Docker and Kubernetes support
- π§ͺ Full test coverage with automated testing
- π Status check endpoint (
/status) - π OpenAPI 3 spec generation in html or any format
mkdir my-api && cd my-api
go mod init github.com/yourusername/my-api
go get github.com/nicolasbonnici/gorest@latestCreate gorest.yaml in your project root:
server:
scheme: "${SERVER_SCHEME:-http}"
host: "${SERVER_HOST:-localhost}"
port: "${SERVER_PORT:-8000}"
environment: "${ENV:-development}"
database:
url: "${DATABASE_URL}"
pagination:
default_limit: "${PAGINATION_DEFAULT_LIMIT:-10}"
max_limit: "${PAGINATION_MAX_LIMIT:-1000}"
plugins:
- name: auth
enabled: true
config:
jwt_secret: "${JWT_SECRET}"
jwt_ttl: 900
codegen:
output:
models: "generated/models"
resources: "generated/resources"
dtos: "generated/dtos"
openapi: "generated/openapi"
config: "generated/config"
enums:
enabled: true
auth:
enabled: true
defaults:
GET: true
POST: true
PUT: true
DELETE: true
endpoints:
- name: posts
GET: falseSet required environment variables:
# Required (no defaults)
export DATABASE_URL="postgres://user:pass@localhost:5432/mydb?sslmode=require"
export JWT_SECRET=$(openssl rand -base64 32)
# Optional (defaults shown in gorest.yaml above)
export ENV="production" # default: development
export SERVER_SCHEME="https" # default: http
export SERVER_HOST="api.example.com" # default: localhost
export SERVER_PORT="8080" # default: 8000
export PAGINATION_DEFAULT_LIMIT="20" # default: 10
export PAGINATION_MAX_LIMIT="5000" # default: 1000Or use a .env file (dotenv support):
# Required
DATABASE_URL=postgres://user:pass@localhost:5432/mydb?sslmode=require
JWT_SECRET=your-secret-key-here
# Optional (override defaults)
ENV=production
SERVER_SCHEME=https
SERVER_HOST=api.example.com
SERVER_PORT=8080
PAGINATION_DEFAULT_LIMIT=20
PAGINATION_MAX_LIMIT=5000π Full configuration documentation β
GoREST supports bash-style environment variable interpolation with default fallback values:
Syntax:
${VAR}- Use environment variable VAR (leaves${VAR}unchanged if not set)${VAR:-default}- Use environment variable VAR, or "default" if not set
Examples:
server:
# Will use environment variable or fallback to default
port: "${SERVER_PORT:-8000}"
host: "${SERVER_HOST:-localhost}"
# Required variable (no default)
environment: "${ENV}"
database:
# Complex defaults work too
url: "${DATABASE_URL:-postgres://user:pass@localhost:5432/dev?sslmode=disable}"
pagination:
# Numeric defaults
default_limit: "${PAGINATION_DEFAULT_LIMIT:-10}"
max_limit: "${PAGINATION_MAX_LIMIT:-1000}"
plugins:
- name: auth
config:
# Empty default
jwt_secret: "${JWT_SECRET:-}"Behavior:
- If the environment variable is set (even to an empty string), its value is used
- If the environment variable is not set and a default is provided, the default is used
- If the environment variable is not set and no default is provided, the original
${VAR}string remains
Note: Environment variable interpolation only works for string fields in the configuration. Integer fields like port, default_limit, and max_limit must be specified as numeric values directly in the YAML file.
go run github.com/nicolasbonnici/gorest/cmd/codegen@latest allpackage main
import (
"github.com/yourusername/my-api/generated/resources"
"github.com/nicolasbonnici/gorest"
)
func main() {
cfg := gorest.Config{
ConfigPath: ".",
RegisterRoutes: resources.RegisterGeneratedRoutes,
}
gorest.Start(cfg)
}go run main.goYour API is now running at: ${SERVER_SCHEME}://${SERVER_HOST}:${SERVER_PORT}/
- π API specs: ${SERVER_SCHEME}://${SERVER_HOST}:${SERVER_PORT}/openapi
- π Status: ${SERVER_SCHEME}://${SERVER_HOST}:${SERVER_PORT}/status
(With default values: http://localhost:8000/)
Import GoREST packages directly in your Go projects:
go get github.com/nicolasbonnici/gorest@latest| Package | Description |
|---|---|
crud |
Type-safe CRUD operations with hooks |
database |
Multi-database abstraction |
expand |
Relation expansion (IRI to object) |
filter |
Query filtering & ordering |
serializer |
JSON-LD response serialization |
hooks |
Lifecycle hooks for business logic |
plugin |
Plugin interfaces |
pluginloader |
Plugin factory & loading |
pagination |
Hydra-compliant pagination |
response |
HTTP response helpers |
migrations |
Database migration system |
fixtures |
Test fixture management |
import (
"github.com/gofiber/fiber/v2"
"github.com/nicolasbonnici/gorest/database"
"github.com/nicolasbonnici/gorest/crud"
auth "github.com/nicolasbonnici/gorest-auth"
)
type User struct {
ID string `json:"id" db:"id"`
Email string `json:"email" db:"email"`
}
func (User) TableName() string { return "users" }
func main() {
db, _ := database.Open("postgres", "postgres://...")
defer db.Close()
userCRUD := crud.New[User](db)
app := fiber.New()
app.Get("/users", auth.RequireAuth("secret", func(c *fiber.Ctx) error {
ctx := auth.Context(c)
result, _ := userCRUD.GetAllPaginated(ctx, crud.PaginationOptions{Limit: 10})
return c.JSON(result.Items)
}))
app.Listen(":8000")
}π Full API documentation on pkg.go.dev
- Configuration β - YAML configuration, environment overrides, and templates
- Plugins β - Plugin system, built-in plugins, and custom plugin creation
- DTOs & Field Control β - Control field visibility with
dtotags - Filtering & Ordering β - Query filtering, comparison operators, and ordering
- Relation Expansion β - Expand IRI references to full nested objects
- JSON-LD Support β - Semantic web support and content negotiation
- Hooks System β - Lifecycle hooks for custom business logic
- Database Migrations β - Migration system with multi-database support
- Fixtures β - Test fixture management
# Filter by status
GET /todos?status=active
# Multiple filters with comparison
GET /todos?status=active&priority[gte]=5
# Order results
GET /todos?order[created_at]=desc
# Combine all
GET /todos?status=active&priority[gte]=5&order[created_at]=desc&limit=10π Full filtering documentation β
# IRI reference (default)
GET /todos/123
# Returns: { "user": "/users/456", ... }
# Expand to full object
GET /todos/123?expand[]=user
# Returns: { "user": { "id": "456", "name": "Alice", ... }, ... }π Full expansion documentation β
# Regular JSON
curl -H "Accept: application/json" http://localhost:8000/todos/123
# JSON-LD with semantic context
curl -H "Accept: application/ld+json" http://localhost:8000/todos/123π Full JSON-LD documentation β
my-api/
βββ gorest.yaml # Configuration
βββ main.go # Your application
βββ generated/
βββ models/ # DB models
βββ resources/ # REST handlers
βββ dtos/ # Data transfer objects
βββ openapi/ # OpenAPI schema
gorest/
βββ crud/ # Generic CRUD
βββ database/ # Multi-DB abstraction
β βββ postgres/
β βββ mysql/
β βββ sqlite/
βββ migrations/ # Migration system
βββ fixtures/ # Fixture management
βββ expand/ # Relation expansion
βββ filter/ # Query filtering
βββ serializer/ # JSON-LD serialization
βββ codegen/ # Code generation
βββ hooks/ # Lifecycle hooks
βββ plugin/ # Plugin interfaces
βββ pluginloader/ # Plugin loading
βββ middleware/ # Core middleware
βββ pagination/ # Hydra pagination
βββ response/ # HTTP helpers
βββ cmd/codegen/ # CLI tool
# Code Generation
make codegen # Run all code generation
make codegen-models # Generate models only
make codegen-resources # Generate resources & DTOs only
make codegen-openapi # Generate OpenAPI schema only
# Testing
make test-up # Start test databases
make test-schema # Load test schema
make test # Run all tests
make test-coverage # Run tests with coverage
# Benchmarking
make benchmark # Run API performance benchmarksservices:
api:
build: .
ports: ["8000:8000"]
environment:
- DATABASE_URL=${DATABASE_URL}
- JWT_SECRET=${JWT_SECRET}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/status"]
interval: 30supstream gorest {
server localhost:8000;
}
server {
listen 443 ssl;
server_name api.example.com;
location / {
proxy_pass http://gorest;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}livenessProbe:
httpGet:
path: /status
port: 8000
initialDelaySeconds: 10
periodSeconds: 30- Passwords: bcrypt hashing with automatic salts
- JWT: 32+ character secrets required
- CORS: Configurable origins
- Rate Limiting: Configurable per-IP limits
- SQL Injection: Parameterized queries
- Input Validation: go-playground/validator support
- Security Headers: X-Frame-Options, CSP, HSTS, etc.
See CONTRIBUTING.md for guidelines.
Quick start:
git clone https://github.com/YOUR_USERNAME/gorest.git
cd gorest
make test-up && make test-schema && make testSee CHANGELOG.md for release history.
MIT β free to use in your projects π