Golang: Implementing push notifications using FCM
Published: 2022-08-28 17:30:05

**1. Basic Introduction to firebase and a device token**
The device token is the main contestant, responsible for pushing notifications. It’s not a fancy word, it’s simply an id that is unique for each device. When we install any application, our device’s unique token is being stored on their server, using which they can notify us.

Firebase is the tool, used for pushing notifications to apps/mobiles/tablets.
It provides a setting to configure the cloud messaging (FCM) service, which is used for push notifications.

Note: The firebase config files used at the app side (google_services.json file for android and GoogleService-Info.plist for iOS) and service_account key must be created for the same project from the firebase console.

In this blog, we will explore how push notifications are sent using Golang and Firebase.

Let’s jump to implementation.

**2. Configure Firebase auth key**
Required packages:
firebase.google.com/go
firebase.google.com/go/messaging
It’s always better to use sensitive stuff in an encrypted format. To serve that purpose I’ve stored the service account key in format base64 encoded as an environment variable.

Here, FIREBASE_AUTH_KEY contains a base64 encoded service account key.

First, let’s decode the service account key.

```golang
func getDecodedFireBaseKey() ([]byte, error) {
  
  fireBaseAuthKey := os.Getenv("FIREBASE_AUTH_KEY")
  
  decodedKey, err :=  base64.StdEncoding.DecodeString(fireBaseAuthKey)
  if err != nil {
     return nil, err
  }
  
  return decodedKey, nil
}
```
The above method will return decoded service account key that will be used in the next step.

Retrieve decoded key and Initialize firebase app, using below code.

```golang
decodedKey, err := getDecodedFireBaseKey()
if err != nil {
   return err
}

opts :=  []option.ClientOption{option.WithCredentialsJSON(decodedKey)}

// Initialize firebase app
app, err := firebase.NewApp(context.Background(), nil, opts...)

if err != nil {
   log.Debug("Error in initializing firebase app: %s", err)
   return err
}
```

**3. Initialize firebase client**
Create fcmClient for messaging(pushing notifications).

```golang
fcmClient, err := app.Messaging(context.Background())

if err != nil {
   return err
}
```
Finally, let’s write a code to send a notification.

**4. Send Push notifications to a single device**
```golang
response, err := fcmClient.Send(context.Background(), &messaging.Message{
  
  Notification: &messaging.Notification{
    Title: "Congratulations!!",
    Body: "You have just implement push notification",
  },
    Token: "sample-device-token", // it's a single device token
})

if err != nil {
     return err
}
```

The above code will send a push notification to a single device.

**5. Send Push notifications to multiple devices**
Consider a scenario if you want to notify multiple devices. It will be almost the same as we send a push notification to a single device, just need to replace fcmClient’s Send() method with SendMulticast().

```golang
response, err := fcmClient.SendMulticast(context.Background(), &messaging.MulticastMessage{
   Notification: &messaging.Notification{
     Title: "Congratulations!!",
     Body:  "You have just implement push notification",
   },
   Tokens: deviceTokens, // it's an array of device tokens
  })

  if err != nil {
     return err
  }

log.Debug("Response success count : ", response.SuccessCount)
log.Debug("Response failure count : ", response.FailureCount)
```
Yay !! You have implemented push notifications in your Golang project 🎊.
The response variable will contain the success count and failure count of sent notifications.

Find the full code at FCM with Golang. Invoke SendPushNotification() and boom !! Check a notification received in the application.

Meanwhile, you can also check to debug logs, as it has SuccessCount and failureCount. It will help to verify that notifications are pushed to how many tokens. In case of finding failureCount > 0, you must verify whether you’re giving a valid device token or not.