# Notification SDK A comprehensive Go SDK for interacting with the Tender Management notification service. This SDK provides a clean, type-safe interface for sending various types of notifications including emails, SMS, push notifications, and OTP messages. ## Features - **Multiple Notification Types**: Support for EMAIL, SMS, PUSH, and OTP notifications - **Automatic Retries**: Configurable retry mechanism with exponential backoff - **Structured Logging**: Built-in logging with structured fields - **Fluent API**: Builder pattern for constructing complex notifications - **Batch Operations**: Send multiple notifications efficiently - **Type Safety**: Full type safety with comprehensive validation - **Error Handling**: Detailed error types and proper error wrapping - **Configuration**: Flexible configuration via environment variables or code - **Health Checks**: Built-in health checking capabilities ## Installation ```bash go get your-module/pkg/notification ``` ## Quick Start ### Basic Usage ```go package main import ( "context" "log" "your-module/pkg/notification" "your-module/pkg/logger" // Your logger implementation ) func main() { // Create configuration config := notification.DefaultConfig() config.BaseURL = "http://127.0.0.1:9095" // Your notification service URL // Create logger (implement notification.Logger interface) logger := logger.New() // Your logger implementation // Create SDK sdk, err := notification.NewSDK(config, logger) if err != nil { log.Fatal("Failed to create notification SDK:", err) } ctx := context.Background() // Send a simple email err = sdk.QuickEmail(ctx, "user@example.com", "Hello World!") if err != nil { log.Printf("Failed to send email: %v", err) } } ``` ### Environment Configuration Set environment variables for automatic configuration: ```bash export NOTIFICATION_BASE_URL="http://127.0.0.1:9095" export NOTIFICATION_TIMEOUT="30s" export NOTIFICATION_RETRY_ATTEMPTS="3" export NOTIFICATION_RETRY_DELAY="2s" export NOTIFICATION_ENABLE_LOGGING="true" export NOTIFICATION_USER_AGENT="MyApp-NotificationSDK/1.0" ``` Then load configuration: ```go import "your-module/pkg/config" // Load configuration from environment cfg, err := config.LoadConfig(".", ¬ification.Config{}) if err != nil { log.Fatal("Failed to load config:", err) } sdk, err := notification.NewSDK(cfg, logger) ``` ## API Reference ### Configuration ```go type Config struct { BaseURL string `env:"NOTIFICATION_BASE_URL"` Timeout time.Duration `env:"NOTIFICATION_TIMEOUT"` RetryAttempts int `env:"NOTIFICATION_RETRY_ATTEMPTS"` RetryDelay time.Duration `env:"NOTIFICATION_RETRY_DELAY"` EnableLogging bool `env:"NOTIFICATION_ENABLE_LOGGING"` UserAgent string `env:"NOTIFICATION_USER_AGENT"` } ``` ### Creating SDK Instance ```go // With default configuration sdk, err := notification.NewSDK(nil, logger) // With custom configuration config := ¬ification.Config{ BaseURL: "http://localhost:9095", Timeout: 30 * time.Second, RetryAttempts: 3, RetryDelay: 2 * time.Second, EnableLogging: true, UserAgent: "MyApp/1.0", } sdk, err := notification.NewSDK(config, logger) // With custom HTTP client httpClient := &http.Client{Timeout: 10 * time.Second} sdk, err := notification.NewSDKWithClient(config, httpClient, logger) ``` ### Sending Notifications #### Simple Notifications ```go ctx := context.Background() // Email response, err := sdk.SendEmail(ctx, "user@example.com", "Welcome!", "user123") // SMS response, err := sdk.SendSMS(ctx, "+1234567890", "Your code: 1234", "user123") // Push Notification response, err := sdk.SendPush(ctx, "device_token_here", "New message!", "user123") // OTP response, err := sdk.SendOTP(ctx, "+1234567890", "Your OTP: 5678", "user123") ``` #### Quick Notifications (without user ID) ```go // Quick methods for simple use cases err := sdk.QuickEmail(ctx, "user@example.com", "Hello!") err := sdk.QuickSMS(ctx, "+1234567890", "Hello!") err := sdk.QuickPush(ctx, "device_token", "Hello!") err := sdk.QuickOTP(ctx, "+1234567890", "Code: 1234") ``` #### Custom Notifications ```go request := ¬ification.NotificationRequest{ EventType: notification.EventTypeEmail, Message: "Custom notification message", Methods: notification.NotificationMethods{ Email: "user@example.com", SMS: "+1234567890", // Optional: multiple delivery methods }, UserID: "user123", } response, err := sdk.SendNotification(ctx, request) ``` ### Fluent Builder API ```go // Build and send notification using fluent API response, err := sdk.NewBuilder(). SetEventType(notification.EventTypeEmail). SetMessage("Welcome to our service!"). SetEmail("user@example.com"). SetUserID("user123"). Send(ctx) // Build without sending request, err := sdk.NewBuilder(). SetEventType(notification.EventTypeSMS). SetMessage("Your verification code: 1234"). SetSMS("+1234567890"). SetUserID("user123"). Build() if err == nil { response, err := sdk.SendNotification(ctx, request) } ``` ### Batch Operations ```go // Prepare multiple requests requests := []*notification.NotificationRequest{ { EventType: notification.EventTypeEmail, Message: "Welcome email", Methods: notification.NotificationMethods{Email: "user1@example.com"}, UserID: "user1", }, { EventType: notification.EventTypeSMS, Message: "Welcome SMS", Methods: notification.NotificationMethods{SMS: "+1234567890"}, UserID: "user2", }, } // Send batch batchResponse, err := sdk.SendBatch(ctx, requests) if err != nil { log.Printf("Batch failed: %v", err) } else { log.Printf("Batch completed: %d success, %d failed", batchResponse.Success, batchResponse.Failed) // Check individual results for _, resp := range batchResponse.Responses { if !resp.Success { log.Printf("Request %d failed: %s", resp.Index, resp.Error) } } } ``` ### Health Checks ```go // Check if notification service is available err := sdk.Health(ctx) if err != nil { log.Printf("Notification service is unhealthy: %v", err) } else { log.Println("Notification service is healthy") } ``` ## Event Types The SDK supports the following notification types: - `notification.EventTypeEmail` - Email notifications - `notification.EventTypeSMS` - SMS notifications - `notification.EventTypePush` - Push notifications - `notification.EventTypeOTP` - OTP notifications ## Error Handling The SDK provides detailed error types for different scenarios: ```go response, err := sdk.SendEmail(ctx, "invalid-email", "Hello!", "user123") if err != nil { switch e := err.(type) { case notification.ErrHTTP: log.Printf("HTTP error %d: %s", e.StatusCode, e.Message) case notification.ErrValidation: log.Printf("Validation error in field %s: %s", e.Field, e.Message) case notification.ErrRetryExhausted: log.Printf("Retry exhausted after %d attempts: %v", e.Attempts, e.LastError) case notification.ErrInvalidConfig: log.Printf("Configuration error in field %s: %s", e.Field, e.Message) default: log.Printf("Unknown error: %v", err) } } ``` ## Logging The SDK requires a logger that implements the `notification.Logger` interface: ```go type Logger interface { Info(msg string, fields map[string]interface{}) Error(msg string, fields map[string]interface{}) Debug(msg string, fields map[string]interface{}) Warn(msg string, fields map[string]interface{}) } ``` Example logger implementation with logrus: ```go import "github.com/sirupsen/logrus" type LogrusLogger struct { logger *logrus.Logger } func (l *LogrusLogger) Info(msg string, fields map[string]interface{}) { l.logger.WithFields(fields).Info(msg) } func (l *LogrusLogger) Error(msg string, fields map[string]interface{}) { l.logger.WithFields(fields).Error(msg) } func (l *LogrusLogger) Debug(msg string, fields map[string]interface{}) { l.logger.WithFields(fields).Debug(msg) } func (l *LogrusLogger) Warn(msg string, fields map[string]interface{}) { l.logger.WithFields(fields).Warn(msg) } ``` ## Testing The SDK is designed to be easily testable. You can mock the HTTP client: ```go import ( "testing" "net/http" "your-module/pkg/notification" ) // Mock HTTP client type MockHTTPClient struct { DoFunc func(req *http.Request) (*http.Response, error) } func (m *MockHTTPClient) Do(req *http.Request) (*http.Response, error) { return m.DoFunc(req) } // Mock logger type MockLogger struct{} func (l *MockLogger) Info(msg string, fields map[string]interface{}) {} func (l *MockLogger) Error(msg string, fields map[string]interface{}) {} func (l *MockLogger) Debug(msg string, fields map[string]interface{}) {} func (l *MockLogger) Warn(msg string, fields map[string]interface{}) {} func TestSendEmail(t *testing.T) { mockClient := &MockHTTPClient{ DoFunc: func(req *http.Request) (*http.Response, error) { // Return mock response return &http.Response{ StatusCode: 200, Body: io.NopCloser(strings.NewReader(`{"status":"Notification sent"}`)), }, nil }, } config := notification.DefaultConfig() logger := &MockLogger{} sdk, err := notification.NewSDKWithClient(config, mockClient, logger) if err != nil { t.Fatal(err) } response, err := sdk.SendEmail(context.Background(), "test@example.com", "Test", "user123") if err != nil { t.Fatal(err) } if response.Status != "Notification sent" { t.Errorf("Expected 'Notification sent', got %s", response.Status) } } ``` ## Best Practices 1. **Configuration**: Use environment variables for configuration in production 2. **Context**: Always pass context for timeout and cancellation support 3. **Error Handling**: Check specific error types for appropriate handling 4. **Logging**: Implement structured logging for better observability 5. **Retries**: Configure appropriate retry settings based on your use case 6. **Validation**: Let the SDK handle validation, but provide clean input data 7. **Batch Operations**: Use batch operations for sending multiple notifications efficiently ## Examples See the `examples/` directory for complete working examples: - `basic_usage.go` - Basic notification sending - `batch_operations.go` - Batch notification processing - `fluent_api.go` - Using the builder pattern - `error_handling.go` - Comprehensive error handling - `configuration.go` - Different configuration methods ## Contributing 1. Fork the repository 2. Create a feature branch 3. Add tests for new functionality 4. Ensure all tests pass 5. Submit a pull request ## License This SDK is part of the Tender Management system and follows the same license terms.