Function(al) Webhooks with Fn

Abhishek Gupta
Fn Project
Published in
5 min readDec 4, 2018

This post demonstrates how to develop an Fn function that is triggered by a GitHub webhook and posts new release details to Twitter. It covers the general concept, code as well as configuration and deployment of your function.

Once configured and deployed, the serverless function will be invoked in response to a new release in a GitHub repository (thanks to the webhook) and post its details (name, version and URL) to Twitter.

If everything works out well, you should have a tweet similar to this one

notify the ‘twitterverse’ !

Overview

Webhooks in general are

“… user-defined HTTP callbacks… usually triggered by some event…the source site makes an HTTP request to the URL configured for the webhook … ”

As mentioned above, the goal is to send out a tweet in response to a new release in a GitHub repository. GitHub provides webhooks for such use cases using which you can tap into it’s events in (near) real-time — these events include actions like pull requests submitted or edited, a new release published to a repository etc.

In the context of GitHub,

“Webhooks allow you to build or set up GitHub Apps which subscribe to certain events on GitHub.com. When one of those events is triggered, we’ll send a HTTP POST payload to the webhook’s configured URL…”

Pay attention to “we’ll send a HTTP POST payload to the webhook’s configured URL…” — this is where our serverless Fn function kicks in! In this case, it acts as the glue between GitHub and Twitter. It implements the piece of logic which enables the flow where,

  • a developer pushes a new release to GitHub
  • GitHub triggers the Webhook which points to the HTTP endpoint of a Fn function…
  • … which in turn takes care of validating the event before posting the release details to Twitter.

Here is a simple diagram to depict the end-to-end integration.

GitHub to Twitter via Fn function

It’s time to dive into the nitty gritty !

Show me the codez…

The source code for the function along other instructions are available on GitHub

Let’s walk through the code bit by bit — it’s a simple Go function.

ThewebhookHandler function is the entrypoint for our function and it starts by checking the GitHub event type

Then comes the part where it’s ensured that the event was indeed sent (i.e. our function was invoked) by GitHub — we make use of the HMAC hex digest sent via the X-Hub-Signature header. A common (user defined) webhook Secret(in GitHub) is used as the HMAC key — this is provided as a part of the function configuration (github_webhook_secret) and extracted at runtime using fnCtx.Config()[“github_webhook_secret”] (it’s a map).

ThematchSignature function

  • computes the expected HMAC from the payload
  • and compares it with the HMAC (from GitHub) using hmac.Equal.

The function returns with an error if the signatures don’t match.

Finally,

  • the GitHub event payload is converted into a simple newReleaseNotification Go struct
  • and the tweet function posts the details to Twitter using the anaconda client library.

Function func.yaml

The code section cannot be wrapped up without mentioning func.yaml which contains the function metadata.

schema_version: 20180708
name: github-release-handler
version: 0.0.1
runtime: go
entrypoint: ./func
format: http-stream
triggers:
- name: handle-release
type: http
source: /handle-release

Notice the triggers section — it is an array of trigger entities that specific triggers for the function. In this case, we have a single HTTP trigger which provides an endpoint to access the function.

Configuration and deployment

The Deploy the function section in the GitHub repo has the complete details, so here is the TL;DR of what needs to be done to get this up and running.

In terms of pre-requisites, you need to setup the following :

Deploying the function is as simple as executing a few Fn CLI commands :

  • fn start — to start your Fn server

Just make sure you have the Fn server installed on a machine which can be accessed from public Internet, or use ngrok on your local machine to set up a secure tunnel to your localhost.

  • fn create app — to create the app along with the Twitter credentials and GitHub webhook secret passed in as configuration and
  • and fn deploy.

Once the function is deployed, just setup a GitHub webhook to point to it — it’s just a REST call away. The config.url (highlighted below) attribute should point to the HTTP endpoint of the function e.g. http://localhost:8080/t/fn-webhook-app/handle-release.

curl -X POST -u <github_user_id>:<your_github_token_or_password> \
https://api.github.com/repos/<github_user>/<github_repo>/hooks \
-H 'content-type: application/json' \
-d '{
"name": "web",
"active": true,
"events": [
"release"
],
"config": {
"url": "<fn_function_endpoint>",
"secret": "<your_github_webhook_secret>",
"content_type": "json",
"insecure_ssl": 1
}
}'

Please refer to Configure GitHub webhook section in the GitHub repo for details.

Test drive

Again, the Test section in the GitHub repo has details, so I am going to keep this concise.

  • Start by creating a release in your GitHub repository — you can use the GitHub UI or simple REST call.
curl -X POST -u <github_user_id>:<your_github_token_or_password> \
https://api.github.com/repos/<github_user>/<github_repo>/releases \
-H 'content-type: application/json' \
-d '{
"tag_name": "v1.0.0",
"target_commitish": "master",
"name": "v1.0.0",
"body": "Description of the release",
"draft": false,
"prerelease": false
}'
  • if all is well, your function will be triggered and the release details should be posted to Twitter — so please keep an eye out for that!
  • … and you can also check the Recent Deliveries in GitHub Webhooks (UI) for further details (it is helpful even in case you run into issues).
GitHub Webhook > Recent Deliveries

The journey from GitHub to Twitter is simple — thanks to a nice and simple Fn function! Although this example is configured to respond to GitHub releases, the same can be extended/applied to other events such as pull requests, commits etc.

That’s it for now!

Don’t forget to …

Cheers!

--

--

Abhishek Gupta
Fn Project

Principal Developer Advocate at AWS | I ❤️ Databases, Go, Kubernetes