How to create and read Google Webhooks using Ruby

How to create and read Google Webhooks using Ruby

8 min read

Being able to create and read webhooks is critical, as it ensures that our applications won’t waste time on unnecessary server requests. With Ruby, we can delve into exploring Google webhooks.

On this blog post, we’re going to learn how to create and read Google webhooks using Ruby.

What are we going to talk about?

What are Webhooks?

Webhooks are notifications triggered by specific events, such as receiving an email, opening a link within an email, creating or deleting an event, and more. They are crucial because they automatically inform our applications of significant occurrences, eliminating the need for periodic information retrieval at set intervals.

Why are Webhooks important?

A webhook is initiated by the server and sent to your application without the need for your application to explicitly request it. Instead of making multiple requests, your application can simply wait until it receives a webhook. This not only enhances application efficiency but also accelerates processing speed.

In scenarios such as sending an email or creating an event, it is crucial to determine whether the message was opened, if there was a click within the message, or if an event was modified or deleted. Access to this information is instrumental in making informed decisions.

Google Pub/Sub for message sync

We can use Google Pub/Sub to sync Gmail messages between Google and Nylas in real time. While not mandatory, this approach is highly recommended.

Setup Google Pub/Sub

Installing the required packages

As we aim to create a Ruby web application, our best choice is Sinatra, one of the most popular micro-frameworks in the Ruby world. We may need to install additional gems.

$ gem install sinatra
$ gem install sinatra-contrib
$ gem install bundler:2.1.2 #We need this specific version

Once installed, we’re ready to go:

Creating a Reading Webhooks Application with Ruby

Contrary to common belief, before creating a webhook, it’s essential to have the ability to read it. This may seem counterintuitive, but it is practical. When initiating the creation of a webhook, Nylas verifies the existence of a valid account and the legitimacy of the creation request. Without this verification, anyone could create webhooks indiscriminately.

We’re going to use Ruby to create the google webhooks application and deploy it to Koyeb.

Therefore, the initial step is to create the reading application.

Create a folder named ruby_read_webhooks, and inside it, create a file named app.rb:

# frozen_string_literal: true

# Load gems
require 'nylas'
require 'sinatra'
require 'sinatra/config_file'

webhook = Data.define(:id, :date, :title, :description, :participants, :status)
webhooks = []

get '/webhooks' do
  params['challenge'].to_s if params.include? 'challenge'
end

post '/webhooks' do
  # We need to verify that the signature comes from Nylas
  is_genuine = verify_signature(request.body.read, ENV['CLIENT_SECRET'],
                                request.env['HTTP_X_NYLAS_SIGNATURE'])
  unless is_genuine
    status 401
    'Signature verification failed!'
  end

  # Initialize Nylas client
  nylas = Nylas::Client.new(
    api_key: ENV['V3_TOKEN']
  )

  # Query parameters
  query_params = {
    calendar_id: ENV['CALENDAR_ID']
  }

  # We read the webhook information and store it on the data class
  request.body.rewind
  model = JSON.parse(request.body.read)
  event, _request_id = nylas.events.find(identifier: ENV['CALENDAR_ID'], object_id: model['data']['object']['id'], query_params: query_params)
  participants = ''
  event[:participants].each do |elem|
    participants += "#{elem[:email]}; "
  end
  hook = webhook.new(event[:id], event[:date], event[:title], event[:description], participants, event[:status])
  webhooks.append(hook)
  status 200
  'Webhook received'
end

get '/' do
  puts webhooks
  erb :main, locals: { webhooks: webhooks }
end

# We generate a signature with our client secret and compare it with the one from Nylas
def verify_signature(message, key, signature)
  digest = OpenSSL::Digest.new('sha256')
  digest = OpenSSL::HMAC.hexdigest(digest, key, message)
  secure_compare(digest, signature)
end

# We compare the keys to see if they are the same
def secure_compare(a_key, b_key)
  return false if a_key.empty? || b_key.empty? || a_key.bytesize != b_key.bytesize

  l = a_key.unpack "C#{a_key.bytesize}"

  res = 0
  b_key.each_byte { |byte| res |= byte ^ l.shift }
  res.zero?
end

We need a template to display the webhooks. Create a views folder, and inside it, create a file named main.erb:

<style>
.webhook {
	padding: 10px;
    margin: 5px;
    background-color: #f3f3f3
}
.h1 {
    text-align: center;
}
</style>
<title>Nylas Webhooks</title>
<h1 class='h1'>Webhooks</h1>
<% webhooks.each do |item| %>
  <div class='webhook'>
    <p><b>Id:</b> <%= item.id %> | <b>Date:</b> <%= item.date %> | <b>Title:</b> <%= item.title %> | 
          <b>Description:</b> <%= item.description %> | <b>Participants:</b> <%= item.participants %> |
          <b>Status:</b> <%= item.status %></p>

  </div>
<% end %>

Everything is prepared, but the application must be deployed to be accessible from the outside.

Deploying the Reading Webhooks Application with Koyeb

In the past, Heroku would have been a suitable choice; however, its free tier is no longer available. Therefore, it’s time to explore better alternatives.

One such alternative is Koyeb, which requires a card for verifying a newly created account—this can be either a debit or credit card.

Firstly, we should upload our source code to GitHub, place it in a project named ruby-read-webhooks (or your chosen name), and include two essential files: Gemfile and Procfile.

This is Gemfile:

# frozen_string_literal: true

source "https://rubygems.org"
ruby "3.2.2"

gem 'nylas', '6.0.0.beta.1'
gem "sinatra", '3.1.0'
gem "sinatra-contrib", "3.1.0"
gem "rack", '2.2.8'
gem "puma", '6.3.1'

In order to generate a Gemfile.lock file, we need to do the following:

$ bundle _2.1.2_ install

If we’re using a Mac, we need to do this instead:

$ bundle _2.1.2_ lock --add-platform x86_64-linux

And this is the Procfile:

web: bundle exec ruby app.rb

We will also need a folder called config, with a file named puma.rb inside, containing the following code:

workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 5)
threads threads_count, threads_count

Your folder structure should look like this:

Ruby Google Webhooks Folder Structure

Now, we need to move on to Koyeb. When we log in, we will be presented with this screen:

Create a Ruby Webhooks App on Kobeb

Here we need to press Create App + and then choose Github.

Deploy new Koyeb project from Github

We need to select our repository and then simply continue with the next screen:

Select Ruby Webhooks project

Let’s choose our builder (how our code is going to be compiled) and the service type, which in this case is going to be a Web Service.

Choose Web Service as the builder

We need to choose the free instance, then select a region that is closer to our geographical location, and then click on Advanced:

Chose the free instance

We’re going to create some environment variables. Port comes by default, so we need to add the rest:

Creating environment variables

CLIENT_SECRET should be left empty (or set to another value) for now, as we will update it later.Once we’re finished, we should press Deploy. Koyeb will start deploying our application, and this might take a couple of minutes.

Deploy Koyeb app

Our application will be deployed, and we should be able to access it once it’s ready.

Provisioning our Ruby Webhooks application

After launching the application, grab the URL and open it in a web browser. It will be empty, as we have yet to define any webhooks.

Empty page with no webhooks

Creating the Create Webhooks Application with Ruby

Now that our Read Webhooks application is up and running, it’s time to create the Webhooks application.

Create a new file and name it Webhooks_V3.rb:

# frozen_string_literal: true

# Load gems
require 'dotenv/load'
require 'nylas'

# Initialize Nylas client
nylas = Nylas::Client.new(
  api_key: ENV['V3_TOKEN']
)

# Identifier

# Request Body
request_body = {
  trigger_types: [Nylas::WebhookTrigger::EVENT_CREATED],
  webhook_url: '<YOUR_WEBHOOK_URL>/webhook',
  description: 'My first webhook',
  notification_email_address: ENV['GRANT_ID']
}

webhooks, = nylas.webhooks.create(request_body: request_body)
puts webhooks

Running the Create Webhooks Application

In the terminal window, enter this command:

$ ruby Webhooks_V3.rb

Copy the value of the webhook_secret variable, as we need it to update our webhook service.

Create a Ruby Webhook

With the webhook_secret value, update the CLIENT_SECRET environment variable. The deployment step will be launched automatically.

Each time a new event is created, our application will be able to display it.

Reading Ruby Webhooks
Ruby Webhooks upclose

What’s next?

Utilizing Ruby, Sinatra and Koyeb and Bruno to create and read Google webhooks was a great experience.

Do you have any comments or feedback? Please use our forums 😎

Here’s the repo for Read Ruby Webhooks and Create Ruby Webhooks.

Don’t miss the action, join our LiveStream Coding with Nylas!

Related resources

Build mail merge and email templates using TinyMCE Rich Text Editor

Learn how to build Mail Merge and Email Template functionality in your email workflow using TinyMCE Rich Text Editor.

Send emails using TinyMCE Rich Text Editor

Learn how to improve your email workflow using TinyMCE Rich Text Editor.

How to create and read webhooks with PHP, Koyeb, and Bruno

Create and read your webhooks using PHP and Leaf PHP, test them using Bruno, and publish them using Koyeb. Here’s the full guide.