This module provides a structured way to register and manage PocketBase event hooks in your application.
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.
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
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
}OnRecordCreate- Triggered when records are createdOnRecordUpdate- Triggered when records are updatedOnRecordDelete- Triggered when records are deleted- Collection-specific variants available
OnCollectionCreate- Triggered when collections are createdOnCollectionUpdate- Triggered when collections are updatedOnCollectionDelete- Triggered when collections are deleted
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
OnMailerSend- Triggered when emails are sent
OnRealtimeConnect- Triggered when realtime clients connectOnRealtimeDisconnect- Triggered when realtime clients disconnectOnRealtimeSubscribe- Triggered when realtime subscriptions are createdOnRealtimeMessage- Triggered when realtime messages are sent
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)
})
}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)
})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)
},
})- 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
- 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
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()
}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()
})