Why Lokstra?
Understanding the problems Lokstra solves and when to use it
π€ The Problem
Building REST APIs in Go, you typically face these challenges:
1. Standard Library is Too Low-Level
// stdlib net/http - verbose boilerplate
func main() {
mux := http.NewServeMux()
// Manual routing
mux.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
http.Error(w, "Method not allowed", 405)
return
}
// Manual JSON parsing
var users []User
// ... database code ...
// Manual JSON encoding
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
})
http.ListenAndServe(":8080", mux)
}
Problems:
- Too much boilerplate
- Manual request/response handling
- No built-in middleware system
- No dependency injection
2. Popular Frameworks Have Limitations
Gin / Echo / Chi
Great frameworks, but:
// Handler signature is fixed
func GetUsers(c *gin.Context) {
// Must use c.JSON(), c.Bind(), etc
// Locked into framework-specific types
}
Problems:
- β Fixed handler patterns
- β No built-in service layer
- β No dependency injection
- β Config-driven deployment limited
- β Hard to migrate monolith β microservices
3. Enterprise Frameworks Too Heavy
Complex frameworks with:
- Too many concepts to learn
- Over-engineered for simple APIs
- Steep learning curve
- Overkill for most projects
π‘ The Lokstra Solution
Lokstra addresses these problems with a balanced approach:
1. Flexible Handler Signatures
Problem: Most frameworks force one pattern
Lokstra: Write handlers that make sense for your use case
// Simple - no params, no errors
r.GET("/ping", func() string {
return "pong"
})
// With error handling
r.GET("/users", func() ([]User, error) {
return db.GetAllUsers()
})
// With request binding
r.POST("/users", func(req *CreateUserRequest) (*User, error) {
return db.CreateUser(req)
})
// Full control
r.GET("/complex", func(ctx *request.Context) (*response.Response, error) {
// Access headers, cookies, etc.
return response.Success(data), nil
})
29 different handler forms supported! Use what fits your needs.
2. Service-First Architecture
Problem: Business logic scattered in handlers
Lokstra: Services are first-class citizens
// Define service
type UserService struct {
DB *Database
}
// Business logic in service
func (s *UserService) GetAll() ([]*User, error) {
return s.DB.FindAll()
}
// β Not optimal - looks up service in map on EVERY request
r.GET("/users", func() ([]*User, error) {
users := lokstra_registry.GetService[*UserService]("users")
return users.GetAll()
})
// β
Optimal - service-level lazy loading (recommended)
var userService = service.LazyLoad[*UserService]("users")
r.GET("/users", func() ([]*User, error) {
return userService.MustGet().GetAll()
})
// First call: Creates service & resolves dependencies
// Subsequent calls: Returns cached instance (fast!)
// OR: Auto-generate router from service!
router := lokstra_registry.NewRouterFromServiceType("user-service")
// Creates routes automatically using conventions + metadata
3. Built-in Dependency Injection
Problem: Manual dependency wiring or external DI containers
Lokstra: Simple, built-in DI with lazy loading
Simple Registration (No Dependencies)
// Register simple service
lokstra_registry.RegisterServiceType("db-factory",
NewDatabase, nil)
lokstra_registry.RegisterLazyService("db",
"db-factory", nil)
With Dependencies (Factory Pattern)
// Register service with dependencies
lokstra_registry.RegisterServiceFactory("users-factory",
func() any {
return &UserService{
DB: service.LazyLoad[*Database]("db"),
}
})
lokstra_registry.RegisterLazyService("users",
"users-factory",
map[string]any{
"depends-on": []string{"db"},
})
Use in Handlers with Lazy Loading
// β Not optimal: Registry lookup on every request
r.GET("/users", func() ([]User, error) {
users := lokstra_registry.GetService[*UserService]("users")
return users.GetAll() // Map lookup happens on EVERY request
})
// β
Optimal: Cached service resolution (recommended)
var userService = service.LazyLoad[*UserService]("users")
r.GET("/users", func() ([]User, error) {
return userService.MustGet().GetAll() // Cached after first access
})
Why service.LazyLoad is faster:
- First call: Looks up service, caches reference
- Subsequent calls: Returns cached instance (zero map lookup)
- Thread-safe: Safe for concurrent requests
- Zero allocation: No repeated registry lookups
Benefits:
- β No external framework needed
- β Type-safe with generics
- β Lazy loading (efficient)
- β Testable (easy mocking)
- β Auto-wiring with YAML config
4. Deploy Anywhere Without Code Changes
Problem: Monolith β Microservices requires rewrite
Lokstra: Configure deployment, not code
# Same code, different deployment!
deployments:
# Monolith: All services in one server
monolith:
servers:
api-server:
addr: ":8080"
published-services:
- users
- orders
- payments
# Microservices: Separate servers per service
microservices:
servers:
user-server:
base-url: "http://localhost"
addr: ":8001"
published-services: [users]
order-server:
base-url: "http://localhost"
addr: ":8002"
published-services: [orders, payments]
Change deployment with just a flag:
./app -server "monolith.api-server" # Run as monolith
./app -server "microservices.user-server" # User microservice
./app -server "microservices.order-server" # Order microservice
One binary, infinite architectures!
5. Annotation-Driven Development (Zero Boilerplate)
Problem: Setting up services with DI and routing requires tons of boilerplate
Lokstra: Annotations like NestJS decorators, but with zero runtime cost!
The Traditional Way (70+ Lines!)
// 1. Define service
type UserService struct {
DB *Database
}
// 2. Create factory
func UserServiceFactory(deps map[string]any, config map[string]any) any {
return &UserService{
DB: deps["db"].(*Database),
}
}
// 3. Register factory
lokstra_registry.RegisterServiceFactory("user-service-factory",
createUserServiceFactory())
// 4. Register lazy service
lokstra_registry.RegisterLazyService("user-service",
"user-service-factory",
map[string]any{"depends-on": []string{"db"}})
// 5. Create router
func setupUserRouter() *lokstra.Router {
userService := lokstra_registry.GetService[*UserService]("user-service")
r := router.NewFromService(userService, "/api")
return r
}
// 6. Register router
lokstra_registry.RegisterRouter("user-router", setupUserRouter())
// ... and more YAML config!
The Lokstra Annotation Way (12 Lines!)
// @RouterService name="user-service", prefix="/api"
type UserServiceImpl struct {
// @Inject "database"
DB *Database
}
// @Route "GET /users"
func (s *UserServiceImpl) GetAll(p *GetAllRequest) ([]User, error) {
return s.DB.GetAllUsers()
}
// @Route "POST /users"
func (s *UserServiceImpl) Create(p *CreateUserRequest) (*User, error) {
return s.DB.CreateUser(p)
}
// Auto-generates: factory, DI wiring, routes, remote proxy!
Results:
- β 83% less code (70+ lines β 12 lines)
- β Like NestJS decorators (familiar DX)
- β Like Spring annotations (proven pattern)
- β But zero runtime cost (compile-time generation)
- β No reflection overhead (pure Go performance)
How It Works
# Run once to generate code
go run . --generate-only
# Or use build scripts (auto-generates before building)
./build.sh # Linux/Mac
.\build.ps1 # Windows PowerShell
.\build.bat # Windows CMD
Generates zz_generated.lokstra.go:
// β
Service factory
func init() {
lokstra_registry.RegisterServiceFactory("user-service-factory", ...)
lokstra_registry.RegisterLazyService("user-service", ...)
}
// β
Router with routes
func init() {
r := lokstra.NewRouter("user-service")
r.GET("/users", ...) // Auto-wired!
lokstra_registry.RegisterRouter("user-service", r)
}
// β
Remote proxy for microservices
type UserServiceRemote struct { ... }
Three Powerful Annotations:
- @RouterService - Define service + router
// @RouterService name="user-service", prefix="/api", mount="/api" type UserServiceImpl struct {} - @Inject - Dependency injection
// @Inject "database" DB *service.Cached[*Database] - @Route - HTTP endpoints
// @Route "GET /users/{id}" func (s *UserServiceImpl) GetByID(p *GetByIDRequest) (*User, error) {}
Comparison with Other Frameworks:
| Framework | Pattern | Runtime Cost | Boilerplate |
|---|---|---|---|
| NestJS | Decorators | High (reflection) | Low |
| Spring | Annotations | High (reflection) | Low |
| Lokstra | Annotations | Zero (codegen) | Very Low |
Lokstra advantage: All the DX benefits, none of the runtime cost!
π Full guide: Example 07 - Enterprise Router Service
π Comparison Matrix
| Feature | stdlib | Gin/Echo | Chi | Lokstra |
|---|---|---|---|---|
| Handler Flexibility | β | β οΈ 1 form | β οΈ 1 form | β 29 forms |
| Auto JSON Response | β | β | β οΈ | β |
| Service Layer | β | β | β | β Built-in |
| Dependency Injection | β | β | β | β Built-in |
| Service Caching | β | β | β | β Lazy Load |
| Service as Router | β | β | β | β Unique |
| Annotations | β | β | β | β 83% less code |
| Config-Driven Deploy | β | β οΈ Limited | β | β Full |
| Multi-Deployment | β | β | β | β 1 binary |
| Middleware System | β οΈ Basic | β | β | β Enhanced |
| Learning Curve | Easy | Easy | Easy | Medium |
| Boilerplate | High | Low | Medium | Very Low |
| Type Safety | β | β οΈ | β | β |
| Performance | β‘β‘β‘ | β‘β‘β‘ | β‘β‘β‘ | β‘β‘β‘ |
Legend:
- β Full support
- β οΈ Partial support
- β Not supported
- β‘ Performance rating
β When to Use Lokstra
Perfect For:
1. REST APIs (Sweet Spot)
// Build REST APIs fast with less code
r := lokstra.NewRouter("api")
r.GET("/users", getUsers)
r.POST("/users", createUser)
r.PUT("/users/{id}", updateUser)
2. Microservices Architecture
# Same code, different servers
servers:
- name: user-service
- name: order-service
- name: payment-service
3. Monolith with Migration Plan
# Start as monolith
deployments:
monolith:
servers:
api-server:
addr: ":8080"
published-services: [users, orders, payments]
# Later: Split to microservices (no code change!)
deployments:
microservices:
servers:
user-server:
addr: ":8001"
published-services: [users]
order-server:
addr: ":8002"
published-services: [orders, payments]
4. Service-Heavy Applications
// Rich business logic in services
type OrderService struct {
Users *UserService
Payments *PaymentService
Inventory *InventoryService
}
5. Multi-Environment Deployments
# dev.yaml
deployments:
dev:
servers:
api-server:
addr: ":3000"
published-services: [users, orders]
# prod.yaml
deployments:
prod:
servers:
api-server:
addr: ":80"
published-services: [users, orders]
π« When NOT to Use Lokstra
Consider Alternatives For:
1. GraphQL-First APIs
Lokstra is optimized for REST. For GraphQL:
- Use
gqlgenorgraphql-go - Lokstra can host GraphQL, but not optimized for it
2. Pure gRPC Services
Lokstra focuses on HTTP/REST. For gRPC:
- Use official
grpc-go - Or use Lokstra for REST + separate gRPC service
3. Static File Servers
// Just serving files? stdlib is enough
http.FileServer(http.Dir("./static"))
4. Learning Go
If youβre new to Go:
- Start with stdlib
net/httpfirst - Learn Go fundamentals
- Then adopt Lokstra for productivity
5. Extreme Performance Requirements
If you need absolute fastest (microseconds matter):
- Use
fasthttpdirectly - Or lightweight frameworks like
fiber - Lokstra is fast, but prioritizes features over raw speed
6. Simple CRUD with Database Only
If itβs just database CRUD with no business logic:
- Consider simpler frameworks (Gin, Echo)
- Or even stdlib + SQL library
- Lokstraβs power shines with complex logic
π― Lokstraβs Philosophy
Core Principles:
1. Convention over Configuration
Smart defaults, configure only when needed:
// Minimal config - just works
r := lokstra.NewRouter("api")
r.GET("/users", getUsers)
2. Service-Oriented
Business logic belongs in services:
// Not in handlers
func handler() { /* business logic */ } // β
// In services
type UserService struct {}
func (s *UserService) CreateUser() {} // β
3. Flexible, Not Opinionated
Multiple ways to solve problems:
// Use what fits your needs
r.Use(middleware.Direct()) // Option 1
r.Use("middleware_name") // Option 2
4. Production-Ready
Built for real applications:
- Graceful shutdown
- Multi-environment support
- Observability hooks
- Error handling
5. Developer Experience
Make developers happy:
- Clear error messages
- Good debugging tools (
PrintRoutes(),Walk()) - Comprehensive documentation
- Runnable examples
π Getting Started
Convinced? Hereβs what to do next:
1. Quick Evaluation (5 minutes)
π Quick Start Guide - Build your first API
2. Deep Understanding (20 minutes)
π Architecture - How Lokstra works internally
3. Learn by Doing (6-8 hours)
π Examples - 7 progressive examples from basics to production
4. Deep Dive (as needed)
π Router Guide - Comprehensive reference
π Still Deciding?
Common Questions:
Q: Is Lokstra mature enough for production?
A: Yes! Already used in production applications. Active development and maintenance.
Q: Howβs the performance?
A: Comparable to Gin/Echo. Not as fast as raw fasthttp, but fast enough for 99% of use cases.
Q: Can I migrate from Gin/Echo?
A: Yes! Gradual migration is possible. Start with new features in Lokstra, keep existing code.
Q: What about community and support?
A: Growing community, active GitHub discussions, comprehensive docs, and responsive maintainers.
Q: Is it stable? Breaking changes?
A: API is stabilizing. We follow semantic versioning. Breaking changes only in major versions.
οΏ½ Whatβs Coming Next?
Lokstra is actively evolving. Hereβs whatβs on the horizon:
Next Release Priorities
π¨ HTMX Support - Modern Web Apps Made Easy
Build interactive web applications without complex JavaScript:
// Coming soon!
r.GET("/users", func() templ.Component {
users := userService.GetAll()
return views.UserList(users) // Returns HTMX-ready component
})
r.POST("/users", func(req *CreateUserReq) templ.Component {
user := userService.Create(req)
return views.UserRow(user) // Partial update
})
Features:
- Template rendering integration (templ, html/template)
- HTMX helper functions and middleware
- Form handling patterns
- Server-sent events (SSE) support
- Example applications (Todo, Dashboard, etc.)
π οΈ CLI Tools - Developer Productivity
Speed up development with command-line tools:
# Create new project
lokstra new my-api --template=rest-api
# Generate boilerplate
lokstra generate service user
lokstra generate router api
lokstra generate middleware auth
# Development server with hot reload
lokstra dev --port 3000
# Database migrations
lokstra migrate create add_users_table
lokstra migrate up
Features:
- Project scaffolding with templates
- Code generation (services, routers, middleware)
- Hot reload development server
- Migration management
- Testing utilities
π¦ Complete Standard Library - Production Ready
Essential middleware and services out of the box:
Middleware:
// Metrics and monitoring
r.Use(middleware.Prometheus())
r.Use(middleware.OpenTelemetry())
// Authentication
r.Use(middleware.JWT(jwtConfig))
r.Use(middleware.OAuth2(oauthConfig))
r.Use(middleware.BasicAuth(users))
// Rate limiting
r.Use(middleware.RateLimit(100, time.Minute))
// Security
r.Use(middleware.CSRF())
r.Use(middleware.SecureHeaders())
Services:
// Health checks
health := lokstra_registry.GetService[*HealthService]("health")
health.AddCheck("database", dbHealthCheck)
health.AddCheck("cache", cacheHealthCheck)
// Metrics
metrics := lokstra_registry.GetService[*MetricsService]("metrics")
metrics.RecordRequest(duration, statusCode)
// Distributed tracing
tracer := lokstra_registry.GetService[*TracingService]("tracing")
span := tracer.StartSpan(ctx, "user.create")
defer span.End()
Features:
- Prometheus metrics integration
- OpenTelemetry tracing
- JWT/OAuth2 authentication
- Rate limiting with Redis
- Health check endpoints
- CSRF protection
- Security headers
Future Vision
Beyond Next Release:
- π Plugin System - Extend framework with community plugins
- π Admin Dashboard - Built-in API explorer and monitoring
- π GraphQL Support - Alternative to REST APIs
- π WebSocket Support - Real-time communication
- π API Documentation - Auto-generate OpenAPI/Swagger docs
- π§ͺ Testing Utilities - Built-in test helpers and mocks
Community & Contributions
Want to help shape Lokstraβs future?
- π‘ Suggest features: Open GitHub issues
- π Report bugs: Help us improve
- π€ Contribute code: PRs welcome
- π Improve docs: Documentation contributions appreciated
- β Star the repo: Show your support
Visit: github.com/primadi/lokstra
οΏ½π Learn More
- Next: Architecture Overview - Understand how it works
- Or: Quick Start - Start coding now
- Or: Key Features - Deep dive into unique features
Ready to build better APIs? π