The world's slowest write database

Gunar Gessner

Gunar Gessner

Jul 18, 2020

This is a blog post on using GitHub as your app's database.

The world's slowest database is the set of birth records in Chinese villages. It's so slow that millions of Chinese couples still have no idea whether they are officially married. Which makes this is the world's second slowest database ;)

Summary:

  • GitHub Actions allows us to trigger events that mutate the git repository
  • We can leverage GitHub actions to add comments to a JSON file
  • Automatic deployment (e.g. using Vercel) will then update the live version of the app, displaying the new comment
  • This flow is not instantaneous but instead takes a few minutes

Let's first think about why we would want to use GitHub as our database. It is certainly not the most powerful database out there. If you need the simplest possible database, you could consider using the popular NoSQL database like MongoDB.

One advantage of using GitHub is that it is easy to set up, it's free, and allows us to use GitHub's interface to make changes to the data. You may also want to know that GitHub Actions supports scheduled trigger events to run periodically or on a specific date/time.

Let's say you want to add a comment section to your blog. Typically, we'd want to use a JSON file for this, but for the sake of simplicity, we're going to go for a simple txt file that looks like this:

William: The post is excellent!
Lisa: In my opinion, it could be better

To add a comment to this file, we need to add a new line.

Let's take a look at how this would be done using the GitHub Actions interface.

First, we want to create a new GitHub repository that will hold the comments. You can create a GitHub repository using the GitHub interface. Once you have a repository, the next step is to create a new file in the repository. This is the file that will hold the comment data.

Next, we need to create a new GitHub Actions Workflow. Actions workflow is a task automation service where users can add a pre-defined set of steps, which can then be triggered by an event. GitHub Actions Workflow supports on-demand triggers and periodic (cron-like) triggers. You can set up a cron-like trigger to run every minute, day, month, or year.

Our workflow will run on demand, so we'll create a file under .github/workflows/add-comment.yml with the following content:

name: "Add Comment"

on:
  repository_dispatch:
    types: add-comment

jobs:
  build:
    name: Add Comment
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v2
      - name: Append to comments.txt
        run: 'echo "${{ github.event.client_payload.comment }}">>comments.txt'
        # If you want to receive it as JSON instead there's a toJson() utility
        #   run: 'echo "payload: ${{toJson(github.event.client_payload)}}"'
        # However, bash variable expansion hits escaping problems around the double-quotes
        # Personally, I had enough of it and ended up encodeURIComponent'ing the whole thing
      - name: Commit changes
        uses: elstudio/actions-js-build/commit@v3
        with:
          commitMessage: "auto(comments): add comment"

In the above configuration, we're running the check-out action from the actions/checkout module. This action is used to checkout files to your local machine and update the contents of the file to match your repository's version. In our workflow, we want to check out the comments.txt file in our repository. Once the file is updated, we want to commit the file. We've also created a commit message and added a tag with the comment: "auto(comments): add comment"

If you're not familiar with YAML, it is just a data serialization language that is similar to JSON, but uses a lot less characters. After you have saved the YAML file, you need to make sure to save it as a file that has the .yml extension.

You can then trigger your GitHub Actions workflow with the following command:

curl -v -H "Accept: application/vnd.github.v3+json" \
    -H "Authorization: token $GITHUB_ACTIONS_TOKEN" \
    --request POST \
    --data '{"event_type": "newsletter-signup", "client_payload": {"comment": "Lara: This is nice I guess"}}' \
    https://api.github.com/repos/$USERNAME/$REPOSITORY/dispatches

Remember to replace $USERNAME and $REPOSITORY with the correct values. And you can create a $GITHUB_ACTIONS_TOKEN here.

We're using the HTTP POST method to trigger the event. We're sending the eventtype and clientpayload to the GitHub API. The client_payload is simply a JSON string. In the payload, we're adding a comment field with the value "Lara: This is nice I guess"

The response to this will contain the event name, but it will not tell you if the trigger has been successfully processed. So you will need to check the events in your repository's dashboard. Alternatively, you can also easily check the events in the repository using this command:

curl -v -H "Accept: application/vnd.github.v3+json" 
  -H "Authorization: token $GITHUB_ACTIONS_TOKEN" 
  --request GET 
  https://api.github.com/repos/$USERNAME/$REPOSITORY/events

To see if the trigger has been successfully processed, you can check out the repository events. Once you click on the event, it will show the status of the trigger. If the trigger has been successfully processed, the status will show as completed.

I'll leave it to you to figure out how to connect this to your frontend. My suggestion is to create an authenticated serverless endpoint, that receives POST events, massages the data, and POSTs again to GitHub.

I hope this has helped you understand more on using GitHub as your app's database. If you have any questions, feel free to reach out via Twitter or GitHub.


Comments

https://twitter.com/gunar (3 weeks ago)

This is the first comment ever! Lets try some emoji: ✨🚀🌷 And some chars: \",}{][<script> If you can see this message, the commenting system is working. Looking forward to reading your comments! Cheers, Gunar