hooks - Innovix-Matrix-Systems/ims-pocketbase-baas-starter GitHub Wiki
Hooks Module
This module provides a structured way to register and manage PocketBase event hooks in your application.
Overview
The hooks module follows the same pattern as the routes module, organizing event hooks into logical groups and providing dedicated handlers for different types of events.
Structure
internal/
├── hooks/
│ ├── hooks.go # Main hooks registration
└── handlers/
└── hook/
├── record_hooks.go # Record model event handlers
├── collection_hooks.go # Collection model event handlers
├── request_hooks.go # Request event handlers
├── mailer_hooks.go # Mailer event handlers
└── realtime_hooks.go # Realtime event handlers
Usage
1. Register Hooks in Your App
In your main application file (typically internal/app/app.go), call the hooks registration:
import "ims-pocketbase-baas-starter/internal/hooks"
func NewApp() *pocketbase.PocketBase {
app := pocketbase.New()
// Register hooks
hooks.RegisterHooks(app)
return app
}
2. Available Hook Categories
Record Hooks
OnRecordCreate- Triggered when records are createdOnRecordUpdate- Triggered when records are updatedOnRecordDelete- Triggered when records are deleted- Collection-specific variants available
Collection Hooks
OnCollectionCreate- Triggered when collections are createdOnCollectionUpdate- Triggered when collections are updatedOnCollectionDelete- Triggered when collections are deleted
Request Hooks
OnRecordListRequest- Triggered on record list API requestsOnRecordViewRequest- Triggered on record view API requestsOnRecordCreateRequest- Triggered on record create API requestsOnRecordUpdateRequest- Triggered on record update API requestsOnRecordDeleteRequest- Triggered on record delete API requests
Mailer Hooks
OnMailerSend- Triggered when emails are sent
Realtime Hooks
OnRealtimeConnect- Triggered when realtime clients connectOnRealtimeDisconnect- Triggered when realtime clients disconnectOnRealtimeSubscribe- Triggered when realtime subscriptions are createdOnRealtimeMessage- Triggered when realtime messages are sent
3. Creating Custom Hook Handlers
To create a new hook handler:
- Add your handler function to the appropriate file in
internal/handlers/hook/ - Register the handler in
internal/hooks/hooks.go
Example:
// In internal/handlers/hook/record_hooks.go
func HandleCustomRecordEvent(e *core.RecordEvent) error {
// Your custom logic here
e.App.Logger().Info("Custom record event", "id", e.Record.Id)
// Always call e.Next() to continue the execution chain
return e.Next()
}
// In internal/hooks/hooks.go
func registerRecordHooks(app *pocketbase.PocketBase) {
// Add your custom hook registration
app.OnRecordCreate("specific_collection").BindFunc(func(e *core.RecordEvent) error {
return hook.HandleCustomRecordEvent(e)
})
}
4. Collection-Specific Hooks
You can register hooks for specific collections:
// Only trigger for "users" collection
app.OnRecordCreate("users").BindFunc(func(e *core.RecordEvent) error {
return hook.HandleUserCreate(e)
})
// Trigger for multiple collections
app.OnRecordCreate("users", "profiles").BindFunc(func(e *core.RecordEvent) error {
return hook.HandleUserOrProfileCreate(e)
})
5. Hook Execution Order
Hooks are executed in the order they are registered. You can control execution order using the Bind method with priority:
app.OnRecordCreate().Bind(&hook.Handler[*core.RecordEvent]{
Id: "high_priority_handler",
Priority: 100, // Higher numbers execute first
Func: func(e *core.RecordEvent) error {
return hook.HandleHighPriorityEvent(e)
},
})
Best Practices
- Always call
e.Next()- This continues the execution chain - Handle errors gracefully - Return errors to stop execution
- Use appropriate log levels - Debug for verbose, Info for important events
- Avoid blocking operations - Keep hook handlers fast
- Use collection-specific hooks when possible for better performance
- Document your custom hooks - Add comments explaining the purpose
Common Use Cases
- Audit logging - Track all record changes
- Data validation - Additional validation beyond schema
- Notifications - Send emails or push notifications on events
- Data synchronization - Update related records or external systems
- Access control - Additional permission checks
- Analytics - Track user behavior and system usage
- Caching - Invalidate caches when data changes
Error Handling
If a hook handler returns an error, it will stop the execution chain and the original operation will fail. Use this for validation or to prevent unwanted operations:
func HandleRecordCreate(e *core.RecordEvent) error {
// Validation logic
if someCondition {
return errors.New("validation failed")
}
return e.Next()
}
Testing Hooks
When testing, you can temporarily disable hooks or add test-specific hooks:
// In tests, you might want to unbind certain hooks
app.OnRecordCreate().UnbindAll()
// Or add test-specific hooks
app.OnRecordCreate().BindFunc(func(e *core.RecordEvent) error {
// Test-specific logic
return e.Next()
})