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.
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.
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:
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.
Now, we need to move on to Koyeb. When we log in, we will be presented with this screen:
Here we need to press Create App + and then choose Github.
We need to select our repository and then simply continue with the next screen:
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.
We need to choose the free instance, then select a region that is closer to our geographical location, and then click on Advanced:
We’re going to create some environment variables. Port comes by default, so we need to add the rest:
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.
Our application will be deployed, and we should be able to access it once it’s ready.
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.
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.