---
# System prepended metadata

title: Untitled

---

Approach for Workflow Notification using Go-Chi (router)
1. Workflow Overview:
We've developed a comprehensive booking system that integrates multiple services such as Google Calendar, SendGrid for email notifications, and messaging services like Telegram and Slack for real-time notifications. The system is built to be resilient, with error handling and retry mechanisms to ensure reliability. The workflow also includes detailed logging for monitoring and troubleshooting.
2. Core Features:
A. HTTP Server with Chi Router
- Utilizes the chi router for handling HTTP requests.
- Includes middleware for logging and other pre-processing needs.
B. Google Calendar Integration
- Creates an event in the Google Calendar for each booking.
- Implements error handling to manage failures and retries.
C. SendGrid Integration
- Sends confirmation emails to customers using the SendGrid API.
- Has error handling and can reattempt in case of failures.
D. Slack and Telegram Notifications
- Sends real-time notifications to admins for every new booking.
- Notifications on failures enhance monitoring and responsiveness.
E. Error Handling and Retrying Mechanisms
- Includes mechanisms to retry failed operations to ensure resilience.
- Notifies admins via Telegram in case of repeated failures.
F. Detailed Logging with zerolog
- Implements detailed logging for monitoring and debugging.
- Utilizes zerolog for efficient and structured logging.
3. Code Walkthrough:
1. HTTP Server:
```r := chi.NewRouter()
r.Use(middleware.Logger)
r.Post("/book", bookingHandler)
http.ListenAndServe(":8080", r)

```
2. Booking Handler:
```// Handles booking requests, integrates Google Calendar, sends emails and notifications.
func bookingHandler(w http.ResponseWriter, r *http.Request) {
    // ... code for processing the booking, error handling, and retries
}

```
3. Google Calendar Integration:
- Utilizes the Google Calendar API to create events.
- Error handling and retries are in place to manage transient failures.
4. SendGrid Email Sending:
```// Sends emails using SendGrid API
response, err := sendEmailUsingSendGrid(to, subject, content)
if err != nil {
    // Log error and retry
}

```
5. Notifications:
- Telegram and Slack notifications ensure that admins are always informed of new bookings and errors.
6. Error Handling and Retries:
```// Retry mechanism for transient failures
for i := 0; i < maxRetries; i++ {
    err := performTask()
    if err == nil {
        break
    }
    time.Sleep(retryInterval)
}

```
7. Logging with zerolog:
```log.Info().
    Str("event", "booking").
    Msg("New booking received")

```
4. Adaptation and Enhancement:
1. Adaptable to Future Updates:
	- The modular design allows easy adaptations to future updates and changes in integrated services APIs or additional features.
2. Scalability:
	- Can be enhanced to include more features, such as SMS notifications, more detailed error handling, and integrations with other services or databases.
3. Customizable:
	- The workflow and code structure are flexible and can be customized to fit specific business needs and requirements.
Your developer can take this comprehensive example, adapt it to your specific business logic, and extend it as needed. The error handling, retry mechanisms, and detailed logging ensure that the system is reliable and easy to monitor and maintain.
1. Importing Necessary Libraries
```package main

import (
 "bytes"
 "encoding/json"
 "fmt"
 "net/http"
 "os"
 "time"

 "github.com/go-chi/chi"
 "github.com/go-chi/chi/middleware"
 "github.com/rs/zerolog"
 "github.com/rs/zerolog/log"
 "github.com/sendgrid/sendgrid-go"
 "github.com/sendgrid/sendgrid-go/helpers/mail"
)

// Enable pretty console logging
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})

```
2. Struct Definitions
```type BookingInfo struct {
 CustomerName  string `json:"customerName"`
 Email         string `json:"email"`
 BookingDate   string `json:"bookingDate"`
 BookingTime   string `json:"bookingTime"`
 ServiceDetail string `json:"serviceDetail"`
}

type TelegramMessage struct {
 ChatID int    `json:"chat_id"`
 Text   string `json:"text"`
}

```
3. Helper Functions
```func sendEmail(info BookingInfo) error {
 from := mail.NewEmail("Example User", "test@example.com")
 subject := "Booking Confirmation"
 to := mail.NewEmail(info.CustomerName, info.Email)
 plainTextContent := fmt.Sprintf("Hello %s, your booking is confirmed for %s at %s", info.CustomerName, info.BookingDate, info.BookingTime)
 htmlContent := fmt.Sprintf("<strong>Hello %s, your booking is confirmed for %s at %s</strong>", info.CustomerName, info.BookingDate, info.BookingTime)
 message := mail.NewSingleEmail(from, subject, to, plainTextContent, htmlContent)
 client := sendgrid.NewSendClient(os.Getenv("SENDGRID_API_KEY"))
 _, err := client.Send(message)
 return err
}

func sendTelegramNotification(info BookingInfo) error {
 message := TelegramMessage{
  ChatID: 123456, // Replace with your Telegram Chat ID
  Text:   fmt.Sprintf("New booking alert for %s at %s: %s", info.BookingDate, info.BookingTime, info.ServiceDetail),
 }

 messageJSON, err := json.Marshal(message)
 if err != nil {
  return err
 }

 resp, err := http.Post("<https://api.telegram.org/bot><YourBotToken>/sendMessage", "application/json", bytes.NewBuffer(messageJSON))
 if err != nil || resp.StatusCode != 200 {
  return fmt.Errorf("failed to send Telegram message: %v", err)
 }
 return nil
}

```
4. Main Handlers
```func bookingHandler(w http.ResponseWriter, r *http.Request) {
 var info BookingInfo
 err := json.NewDecoder(r.Body).Decode(&info)
 if err != nil {
  http.Error(w, "Invalid request body", http.StatusBadRequest)
  return
 }

 err = sendEmail(info)
 if err != nil {
  log.Error().Err(err).Msg("Error sending email")
  sendTelegramNotification(BookingInfo{
   ServiceDetail: "Failed to send booking confirmation email.",
  })
  return
 }

 err = sendTelegramNotification(info)
 if err != nil {
  log.Error().Err(err).Msg("Error sending Telegram notification")
 }

 _, _ = w.Write([]byte("Booking confirmed, and notifications sent!"))
}

```
5. Main Function
```func main() {
 r := chi.NewRouter()
 r.Use(middleware.Logger)

 r.Post("/book", bookingHandler)

 http.ListenAndServe(":8080", r)
}

```
Notes:
1. Logging: We are using zerolog for logging, which is a zero allocation JSON logger.
2. Error Handling: When the email sending fails, an error is logged and a Telegram notification is sent to inform about the email failure.
3. Middleware: middleware.Logger from chi is being used for request logging.
Replace placeholders like <YourBotToken> with actual values. Also, remember to handle sensitive information like API keys securely, avoiding hardcoding them directly into the source code.
Make sure you have the necessary libraries installed with:
```go get -u github.com/go-chi/chi
go get -u github.com/rs/zerolog
go get -u github.com/sendgrid/sendgrid-go

```
I hope this comprehensive code meets your expectations, and it's ready for further development and adaptation according to the specific needs and environment.
Auth Tokens & Secrets
Of course! I'll provide you with a more organized and structured codebase that's ready for development.
Directory Structure:
```/myapp
│
├── /handlers
│   ├── booking.go
│   └── notifications.go
│
├── /utils
│   ├── secrets.go
│   └── middleware.go
│
├── main.go
│
└── go.mod

```
1. main.go - Entry Point
```package main

import (
 "net/http"
 "myapp/handlers"
 "myapp/utils"

 "github.com/go-chi/chi"
 "github.com/go-chi/chi/middleware"
 "github.com/rs/zerolog"
 "github.com/rs/zerolog/log"
 "os"
)

func init() {
 log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
}

func main() {
 r := chi.NewRouter()
 r.Use(middleware.Logger)
 r.Post("/book", handlers.BookingHandler)

 http.ListenAndServe(":8080", r)
}

```
2. handlers/booking.go - Booking Handler
```package handlers

import (
 "encoding/json"
 "net/http"
 "myapp/utils"

 "github.com/rs/zerolog/log"
)

func BookingHandler(w http.ResponseWriter, r *http.Request) {
 var info utils.BookingInfo
 err := json.NewDecoder(r.Body).Decode(&info)
 if err != nil {
  http.Error(w, "Invalid request body", http.StatusBadRequest)
  return
 }

 err = utils.SendEmail(info)
 if err != nil {
  log.Error().Err(err).Msg("Error sending email")
  utils.SendTelegramNotification(utils.BookingInfo{
   ServiceDetail: "Failed to send booking confirmation email.",
  })
  return
 }

 err = utils.SendTelegramNotification(info)
 if err != nil {
  log.Error().Err(err).Msg("Error sending Telegram notification")
 }

 _, _ = w.Write([]byte("Booking confirmed, and notifications sent!"))
}

```
3. handlers/notifications.go - Notifications Handler
```package handlers

import (
 "bytes"
 "encoding/json"
 "fmt"
 "net/http"
 "myapp/utils"
)

func SendEmail(info utils.BookingInfo) error {
 // ... [Your SendGrid logic]
}

func SendTelegramNotification(info utils.BookingInfo) error {
 // ... [Your Telegram logic]
}

```
4. utils/secrets.go - Constants and Structs
```package utils

const (
 TelegramToken = "1825029617:AAGHKYRuQa1dZlZBA-G-LxwluSOHyU_A9_c"
 SendGridAccountSID = "AC1af86f1a2fd78f5f6e1230c431ac5da9"
 SendGridAuthToken  = "3f29c190378755817cd3c0e529a92cc7"
 SlackWebhookURL = "<https://hooks.slack.com/services/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>"
 GoogleServiceAccountJSON = `{
     // ... [Your provided service account JSON]
 }`
)

type BookingInfo struct {
 CustomerName  string `json:"customerName"`
 Email         string `json:"email"`
 BookingDate   string `json:"bookingDate"`
 BookingTime   string `json:"bookingTime"`
 ServiceDetail string `json:"serviceDetail"`
}

type TelegramMessage struct {
 ChatID int    `json:"chat_id"`
 Text   string `json:"text"`
}

```
4.1 google_service_auth.json
```{
    "type": "service_account",
    "project_id": "api-places-2021",
    "private_key_id": "a47b7bfd506656d2dc90e88aa8e6e6890ba91c20",
    "private_key": "-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXymntWlXdfB88\\ngTdVu9f/eVJSDU0pjelMJSXjNY/lucwGashsO/adVrXGcU/jYkgXSVFTRWza9uaT\\ntz0+j539W9TVgVy2Bpoedx7j53qirRdbttdb4+kuG++mQoSY2D3Ic1XkDHOpeog/\\nu3jMzVg/w3Dt31T/sWc6G7+1TQNW+jX3hKoe3sCPtrRCpwMz+Wtd6SibAuV8GJ6w\\nHjd5Rh8Y9CsKZsTJ9YZZCCs8lE5hHKRNLFDQWQYCd2+ItNYLwKsPGl/meos5mW/B\\nlBM4K+w9+7rTcmdIx5TkLgoD1jbo9sePZa0MpswSZ9EpZ2LL/03SOWC3VpAEVyv5\\nqulISiL9AgMBAAECggEAD9gwMHeCiQkg1ZcDaK6gAGnwnuIGkPTgSnOCPfJkX+2C\\nD5Vr8Ghd+NSJSvqfBTRIJC4iEBgqIb0uGnNBMFubeUvxrou/Wrzbr5xtnAqYsYxx\\n6L/wQQZMW+TMokVFRBMmd9saNyDZnfJNcKGoHXC96oIDMsFiRQKGrPkijNFKLPTu\\nFbeDHp4cZIUn4JMLNVrk+IJBYyQxaK1478yOpNjMIeN80hONqBIdfUI3wuH3tTOg\\nD5zfh2OPzlOaCc/cLKtLdBS6jMK7Li0hdZHSJcMhZC7xMSY2F4EcQhd8QpzBWZkl\\n3QjnmjlRyiq/gAA4Gutq5bfXPFXE6ZRnGYkDExrXIQKBgQDTfNSaDLTq3ABQrIxx\\nlL12XGg1fUf5NCmBila06I6/vShJN1P/SVQcGJAXF5dSrUM6W9XfLc3AGGbS8wyB\\nR8waMUEk/QTuMG2UHCAMmdEkBqDn0L5ulFSXsIA2idgShTAX18PteLpbeMEsayqs\\n1/n3SgNvvxA4ucBbxbgdkW1rtQKBgQC3vQ0Pp4qIB2dXD21Q1KF4HY+yljSYzHKg\\nj70D9BdSYpV7dK63cjHEFjGdBz+SPhvm4kv16O4rr6KBEHp9iPYroKhfHhnSI+p/\\nE6+vqrF7V0NFqpkOdRZOGXTIW9SbE8mzQ/iKzw1oWWpoUSB0H6wOrYeYuTgvuU6t\\nQO3yESA3KQKBgBpCEH+D/l5+rEdX9SQRDKkKdiHWCT6mvFSKIZPaoAasbLkSdopm\\nx1uprRJA6pfoTUWMq3RHUpl8LiAY7z+J84x4+xall5wfRSuzhkMqQe5QKGA/6bT/\\nE7W1w2WCHeLGyJ7dOkVczP6YcpuaPrUxJ6cNeHnCZjg0z+5VETQSn1xVAoGBALPr\\nhRGyPx5LGa+P5LzFKkSDtgXrvh9t/EUr26w2Zmv/K1+T986dHQxlqzmYMnETLqFd\\nMYLhD/BpcViu+TNaXayFCrrxr9kt4F+FuIDtRhSAc9iRYIVetHPPy6KzAbLForpP\\nMd9DN17aSC9UWdI8fXB2DpTHsrRQ4jEXpqlmicRZAoGAAyahqXwhDf6k4AjVlzI7\\nglGXqgQkyj9nrJ4vamqNAnufepog5+xRDuO2hdlJjJ74bF64EJ0wgRq3CiegUSnC\\nGqmyorva74vfQmKi21WmbckOuYtOXVZw2JiMBwYiRw4+WnFjHXHBQpFfGgfRqHNc\\nl1dFsQfEm56u3URJIQeFpQQ=\\n-----END PRIVATE KEY-----\\n",
    "client_email": "31588978191-compute@developer.gserviceaccount.com",
    "client_id": "117240442030593207167",
    "auth_uri": "<https://accounts.google.com/o/oauth2/auth>",
    "token_uri": "<https://oauth2.googleapis.com/token>",
    "auth_provider_x509_cert_url": "<https://www.googleapis.com/oauth2/v1/certs>",
    "client_x509_cert_url": "<https://www.googleapis.com/robot/v1/metadata/x509/31588978191-compute%40developer.gserviceaccount.com>",
    "universe_domain": "googleapis.com"
  }

```
5. utils/middleware.go - Middleware (optional)
```package utils

// ... [Any middleware functions you might need, e.g., for logging, error handling, etc.]

```
6. go.mod - Dependencies
```module myapp

go 1.16

require (
 github.com/go-chi/chi v5.0.2+incompatible
 github.com/rs/zerolog v1.25.0
 github.com/sendgrid/sendgrid-go v3.10.11+incompatible
)

```
This structure is modular and separates different responsibilities into different files and packages, which is a good practice in Go development. To start your development:
1. Create the directories and files as shown above.
2. Populate each file with the provided code.
3. Run go mod init myapp in the myapp directory.
4. Run go get to fetch the dependencies.
5. Run go run main.go to start the server.
Using Templates
1. Organize Your Templates:
Structure your templates directory further:
```/templates
  |- email
  |  |- booking-confirmation.html
  |  |- error-notification.html
  |- slack_telegram
     |- booking-confirmation.txt
     |- error-notification.txt

```
2. Parsing Templates:
You'll need both text/template and html/template packages.
```import (
 "html/template"
 "text/template"
)

// Globally declare your templates
var emailTemplates = template.Must(template.ParseGlob("templates/email/*.html"))
var slackTelegramTemplates = textTemplate.Must(textTemplate.ParseGlob("templates/slack_telegram/*.txt"))

```
3. Rendering a Template:
Create separate functions for rendering each type:
```func renderHTMLTemplate(templateName string, data interface{}) (string, error) {
    var buf bytes.Buffer
    err := emailTemplates.ExecuteTemplate(&buf, templateName, data)
    if err != nil {
        return "", err
    }
    return buf.String(), nil
}

func renderTextTemplate(templateName string, data interface{}) (string, error) {
    var buf bytes.Buffer
    err := slackTelegramTemplates.ExecuteTemplate(&buf, templateName, data)
    if err != nil {
        return "", err
    }
    return buf.String(), nil
}

```
4. Modify Your Handlers:
Use the appropriate render function based on the platform:
```func bookingHandler(w http.ResponseWriter, r *http.Request) {
    var info BookingInfo
    err := json.NewDecoder(r.Body).Decode(&info)
    if err != nil {
        http.Error(w, "Invalid request body", http.StatusBadRequest)
        return
    }

    // For Email
    emailContent, err := renderHTMLTemplate("booking-confirmation.html", info)
    if err != nil {
        log.Error().Err(err).Msg("Error rendering email template")
        return
    }
    err = sendEmail(info.CustomerName, info.Email, emailContent)

    // For Slack and Telegram
    messageContent, err := renderTextTemplate("booking-confirmation.txt", info)
    if err != nil {
        log.Error().Err(err).Msg("Error rendering Slack/Telegram template")
        return
    }
    sendSlackNotification(messageContent)
    sendTelegramNotification(messageContent)
    ...
}

```
5. Testing:
Ensure you test both your HTML/CSS email templates and your plaintext Slack and Telegram templates. This ensures that the content is displayed correctly on all platforms.
6. Advanced Templating:
You can still use conditional blocks, loops, and custom functions in both HTML and plaintext templates. This allows you to dynamically generate content based on your data.
By structuring your templates and creating separate rendering functions for each platform, you can ensure that your notifications are tailored for their intended platform while keeping your codebase clean and maintainable.
Absolutely, I'll incorporate these considerations into the code and workflow.
8. Automated Testing
Add a testing file to your project to handle automated tests.
Create a file named booking_test.go:
```package main

import (
 "testing"
)

func TestBooking(t *testing.T) {
    // TODO: Implement detailed test cases
    bookingID, err := Booking(1) // Sample test
    if err != nil || bookingID == 0 {
        t.Errorf("Failed to create booking")
    }
}

```
9. Continuous Integration (CI)
Create a GitHub Actions workflow for CI. In your repository, create a file at .github/workflows/go.yml:
```name: Go CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Check out code
      uses: actions/checkout@v2

    - name: Set up Go
      uses: actions/setup-go@v2
      with:
        go-version: ^1.16

    - name: Install dependencies
      run: go mod download

    - name: Run tests
      run: go test ./...

```
10. Version Pinning
Ensure dependencies are pinned in the go.mod file.
```module yourmodule

go 1.16

require (
    github.com/sendgrid/rest v2.4.1
    // Other dependencies with their versions
)

```
11. Rollback Mechanism
This will be part of your deployment strategy, either through scripts or managed services like Kubernetes. Here is a simplified example using a script that checks the exit status of your deployment command:
```#!/bin/bash
# deploy.sh

# Deployment command
go deploy

# Check if deployment was successful
if [ $? -eq 0 ]; then
    echo "Deployment successful!"
else
    echo "Deployment failed, rolling back..."
    # Rollback commands, could be reverting to a previous deployment or state
    go deploy --rollback
fi

```
12. Dependency Scanning
GitHub's Dependabot can automatically scan your dependencies. Create .github/dependabot.yml:
```version: 2
updates:
  - package-ecosystem: "gomod"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10

```
13. Automated Dependency Updates
Handled by the dependabot configuration above; it will automatically open pull requests when it finds updates.
14. Documentation
Make sure to include detailed comments in your code and maintain a comprehensive README. For API endpoints, consider tools like Swagger for interactive documentation.
Example of adding comments to your Go code:
