Example 01: Simple Service

Learn service registration and basic access patterns
Time: 10 minutes β€’ Concepts: Service factory, registration, LazyLoad


🎯 What You’ll Learn


πŸš€ Run It

cd docs/01-router-guide/02-service/examples/01-simple-service
go run main.go

Server starts on: http://localhost:3000


πŸ“ Code Walkthrough

Step 1: Define Service

type UserService struct {
    users  []User
    nextID int
}

func (s *UserService) GetAll() ([]User, error) {
    return s.users, nil
}

func (s *UserService) GetByID(id int) (*User, error) {
    for _, user := range s.users {
        if user.ID == id {
            return &user, nil
        }
    }
    return nil, fmt.Errorf("user not found")
}

func (s *UserService) Create(name, email, role string) (*User, error) {
    user := User{
        ID:    s.nextID,
        Name:  name,
        Email: email,
        Role:  role,
    }
    s.users = append(s.users, user)
    s.nextID++
    return &user, nil
}

πŸ’­ Key Points:


Step 2: Create Factory Function

func NewUserService() *UserService {
    return &UserService{
        users: []User{
            {ID: 1, Name: "Alice", Email: "alice@example.com", Role: "admin"},
            {ID: 2, Name: "Bob", Email: "bob@example.com", Role: "user"},
        },
        nextID: 3,
    }
}

πŸ’­ Key Points:


Step 3: Register Service

func main() {
    // Create and register service instance
    userSvc := NewUserService()
    lokstra_registry.RegisterService("users", userSvc)
    
    // ... create router and handlers
}

πŸ’­ Key Points:


Step 4: Access Service with LazyLoad

// Package-level: Cached after first access!
var userService = service.LazyLoad[*UserService]("users")

r.GET("/users", func() (*response.ApiHelper, error) {
    api := response.NewApiHelper()
    
    // Access service - only 1-5ns overhead after first call!
    users, err := userService.MustGet().GetAll()
    if err != nil {
        api.InternalError(err.Error())
        return api, nil
    }
    
    api.Ok(users)
    return api, nil
})

πŸ’­ Key Points:


πŸ§ͺ Test Endpoints

List All Users

curl http://localhost:3000/users

Response:

{
  "status": "success",
  "data": [
    {"id": 1, "name": "Alice", "email": "alice@example.com", "role": "admin"},
    {"id": 2, "name": "Bob", "email": "bob@example.com", "role": "user"},
    {"id": 3, "name": "Charlie", "email": "charlie@example.com", "role": "user"}
  ]
}

Get User by ID

curl http://localhost:3000/users/1

Response:

{
  "status": "success",
  "data": {
    "id": 1,
    "name": "Alice",
    "email": "alice@example.com",
    "role": "admin"
  }
}

Create New User

curl -X POST http://localhost:3000/users \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Dave",
    "email": "dave@example.com",
    "role": "user"
  }'

Response:

{
  "status": "success",
  "message": "User created successfully",
  "data": {
    "id": 4,
    "name": "Dave",
    "email": "dave@example.com",
    "role": "user"
  }
}

Update User

curl -X PUT http://localhost:3000/users/1 \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Alice Updated",
    "email": "alice.new@example.com",
    "role": "admin"
  }'

Delete User

curl -X DELETE http://localhost:3000/users/3

Response:

{
  "status": "success",
  "data": {
    "message": "User deleted successfully"
  }
}

πŸ’‘ Key Concepts

1. Service Pattern

Services encapsulate business logic:

2. Factory Pattern

Factory functions initialize services:

3. LazyLoad Pattern

service.LazyLoad() provides cached access:

4. Registry Pattern

Global service registry:


🎯 Best Practices Demonstrated

βœ… Package-Level LazyLoad

// βœ… GOOD: Package-level, cached forever
var userService = service.LazyLoad[*UserService]("users")

func handler() {
    users := userService.MustGet().GetAll()
}

❌ Function-Level LazyLoad

// ❌ BAD: Created every request, cache useless!
func handler() {
    userService := service.LazyLoad[*UserService]("users")
    users := userService.MustGet().GetAll()
}

βœ… Use MustGet() for Clear Errors

// βœ… GOOD: Clear error message
users := userService.MustGet().GetAll()
// If service not found: "service 'users' not found or not initialized"

❌ Using Get() Without Nil Check

// ❌ BAD: Confusing nil pointer error
users := userService.Get().GetAll()
// If service not found: "runtime error: invalid memory address"

πŸ”— What’s Next?

Continue to:

Related:


Back: Service Guide
Next: 02 - Performance Comparison