How to create and test a GitHub Action that generates Supabase database types
Tags: javascript, opensource, github, tutorial
Published: 2022-05-07 09:32:58

## How to generate types from a Supabase database

On the Supabase documentation, there is a page on [generating types](https://supabase.com/docs/guides/api/generating-types). Following the instructions, the script to run looks something like this. 

> Note the additional `--version=2` parameter. This probably became a mandatory prop after some update to the `openapi-typescript` tool.

```bash
npx openapi-typescript https://{projectId}.supabase.co/rest/v1/?apikey={specialApiKey} --output=types/supabase.ts --version=2
```

The values for the anon key and URL can be found in the Supabase dashboard.

![Screenshot of Supabase project dashboard](https://cdn.hashnode.com/res/hashnode/image/upload/v1649239351647/ANXQsJpXa.png)

Running the script generates a file like [this](https://github.com/lyqht/Billy/blob/main/src/types/supabase.ts). With the **definitions** that are generated there, I could create a type for `Bill` with just the code block below.

```ts
import {definitions} from '../types/supabase';

export type Bill = definitions['Bill'];
```

Most of my project source code still works fine after changing the type. The only code I had to refactor is related to the `deadline` field which is Date type. The **definitions** has the field declared as a string, even though they do acknowledge it is a Date format. 

```ts
Bill: {
    /** Format: date */
    deadline?: string;
}
```

Personally I think this is ok, since this forces you to convert date objects to appropriate ISO strings, so there is less ambiguity about passing the Date object that you have constructed in JS to Supabase. If you don’t like this you could override it in your self-declared type. 

In the same documentation, they also included a section on [how to update types automatically with GitHub Actions](https://supabase.com/docs/reference/javascript/generating-types#update-types-automatically-with-github-actions). This ensures that whenever you update the database, your GitHub action will automatically update the types that you have in your DB. Then, the next time you pull your source code, you would know what are the new changes and how to accommodate them. 

In the docs, there’s a script to be added to the `package.json` as such.

```json
"update-types": "npx openapi-typescript https://your-project.supabase.co/rest/v1/?apikey=your-anon-key --output types/database/index.ts"
```

However, I wasn’t too sure how to replace the values in the package.json script safely with **environmental variables** when I push the source code. I’m not very familiar with bash syntax, but I assume the script should look something like this for my project.

```json
"update-types": : "npx openapi-typescript https://${SUPABASE_URL}/rest/v1/?apikey=${ANON_KEY} --version=2 --output types/database/index.ts"
```

To double confirm the syntax, I decided to use the Sourcegraph Visual Studio Code plugin to look for projects that have implemented this GitHub action.

## Cross-reference code with Sourcegraph Visual Studio Code plugin

The Sourcegraph Visual Studio Code plugin can be installed through the Extensions panel. 


![](https://cdn.hashnode.com/res/hashnode/image/upload/v1649239394629/QM9DB0arX.png)

Once you have it installed, you can find the Sourcegraph icon at the side bar. When you click it, you will see the usual UI to do a universal code search. To find other projects that also generate types, we can pass in a query `npx openapi-typescript`.


![](https://cdn.hashnode.com/res/hashnode/image/upload/v1649239412401/MM0qAP2pv.png)

We see quite a few results, and luckily, in the 3rd project called [tone-row/flowchart-fun](https://github.com/tone-row/flowchart-fun), I see that they have `package.json` script that looks like a promising candidate. They have variables such as  `SB_URL` and `SB_ANON_KEY` which resemble Supabase stuff ✨

```json
"generate:types": "export $(cat .env.local | xargs) && npx openapi-typescript \"${SB_URL}/rest/v1/?apikey=${SB_ANON_KEY}\" --output types/database/index.ts",
```

With this cross-reference and knowledge, we know that we are missing out on wrapping the whole API endpoint in a string with escape characters. Then, we can modify our previous script to match this script. 

```json
"update-types": "npx openapi-typescript \"${SUPABASE_URL}/rest/v1/?apikey=${SUPABASE_ANON_KEY}\" --version=2 --output types/database/index.ts"
```

If we run this script locally via `npm run update-types` , we can see it generates the same output that we have done previously ✨

Out of curiosity, I also want to know if their GitHub workflow follows the same structure that was given in the example given in Supabase docs. The cool thing is with the Sourcegraph plugin, I can **explore the repository in the editor** itself.

Sadly, this project is not using the `generate:types` script that they have written in a GitHub workflow. They’re probably only running the npm script locally. Thankfully with the help of the Supabase documentation folks, at least we don’t have to write the action from scratch. 

## How to create the GitHub workflow

> This section has been merged to Supabase documentation [here](https://supabase.com/docs/guides/api/generating-types) after publication of this article.

To add GitHub action workflows to your project, you need a new folder `.github/workflows` to store the workflows. For the `workflow.yml` that consist the steps for the GitHub action workflow, we will be using the [sample GitHub action workflow](https://supabase.com/docs/reference/javascript/generating-types#update-types-automatically-with-github-actions) on the Supabase documentation as a base. I have **modified** it a little to insert some GitHub secrets as environment variables, you can refer to the comments below.

```yaml
name: Update database types

on:
  schedule:
    # sets the action to run daily. You can modify this to run the action more or less frequently
    - cron: '0 0 * * *'
	# for the workflow to be dispatched manually via GitHub actions dashboards.
  workflow_dispatch:

jobs:
  update:
    runs-on: ubuntu-latest
    env:
        SUPABASE_URL: ${{secrets.SUPABASE_URL}}
        SUPABASE_ANON_KEY: ${{secrets.SUPABASE_URL}}
    steps:
      - uses: actions/checkout@v2
        with:
          persist-credentials: false
          fetch-depth: 0
      - uses: actions/setup-node@v2.1.5
        with:
          node-version: 14
      # -- add echo -- #
      - run: |
          npm run update-types 
          echo "$(cat types/database/index.ts)"
      - name: check for file changes
        id: git_status
        run: |
          echo "::set-output name=status::$(git status -s)"
      - name: Commit files
        if: ${{contains(steps.git_status.outputs.status, ' ')}}
        # -- change git stage filename -- #
        run: |
          git add types/database/index.ts
          git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git config --local user.name "billy-github-actions[bot]"
          git commit -m "Update database types" -a
      - name: Push changes
        if: ${{contains(steps.git_status.outputs.status, ' ')}}
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: ${{ github.ref }}
```

The changes include: 

- Addition of a trigger `workflow_dispatch` so that the workflow can be dispatched manually via GitHub actions dashboards *if* necessary.
- Addition of an `echo` statement to **see the content of the result file** from running `update-types` script
- Pass GitHub action secrets into environment variables.
- Change the filename to be staged 

If you are not familiar with GitHub action secrets, think of it as separate environment variables solely for GitHub actions. This is a screenshot of where you can add them at the settings of your GitHub project.

![Settings > Secrets > GitHub secrets](https://cdn.hashnode.com/res/hashnode/image/upload/v1649239786702/uJmbgzaCP.png)

To deploy the workflow, simply push the `.github/workflows` folder. 

Then you will see the new workflow available in the Actions tab of your GitHub project. When you click on the additional options button, you can manually dispatch the workflow.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1649240835522/EO6FMCWKR.png)

You can also view the logs of each workflow run if you encounter any issues. For example, here in the succeeded job, I can see the `src/types/supabase.ts` file content that is retrieved since we logged it out as part of the steps of the workflow.

![You will see similar content as the definitions file you obtained by manually running the npm script](https://cdn.hashnode.com/res/hashnode/image/upload/v1649240993687/0XKnycv5B.png)

In the next section, I’ll introduce you to a handy tool that I learnt while building [a custom composite GitHub action](https://github.com/lyqht/article-badge-counter-workflow) to **test GitHub actions locally**.

## How to test GitHub Actions locally with act

**[act](https://github.com/nektos/act)** is a tool that lets you test GitHub actions locally. The benefit of this is that you get faster feedback without clogging up the GitHub Action Runner history on your project. 

Refer to the [GitHub repository README.md](https://github.com/nektos/act) to see how to install **act**. You would need Docker installed too. The first time you start up act, you will be asked to choose the image that you want to create. For this GitHub Action, to **test the functionality of updating the database types**, the **Micro** image should be sufficient. 

![3 choices given to you for the image, can refer to docs.](https://cdn.hashnode.com/res/hashnode/image/upload/v1649239856663/HLUyBPUdG.png)

After this config is completed, you can navigate to `~/.actrc` to see the config for your docker image.

```bash
-P ubuntu-latest=node:16-buster-slim
-P ubuntu-20.04=node:16-buster-slim
-P ubuntu-18.04=node:16-buster-slim
```

> Note that the Micro image does not have the full capability of a GitHub Action runner, so you will see errors related to git commands. I don’t want to explode my computer’s memory with the **Large** image **(~20GB)**, but you can try if you like.

To run this workflow locally with *act*, we can run this bash command.

```bash
act -j update --secret-file .env
```we can pass in the following parameters:

Explanation of parameters

- `-j ${jobName}`
    - we only have 1 job declared in this workflow, so we can pass the **update** job
- `--secret-file ${filePath}`
    - for the project, I am already using `.env` for all the environment variables, so I can pass this same file for secrets. 
    ```bash
    SUPABASE_URL=your_url
    SUPABASE_ANON_KEY=hehe
    ```
    - If you rather not have .env files locally for some reason, you can also pass variables manually with the parameter `-s SUPBASE_URL=your_url -s SUPABASE_ANON_KEY=hehe`
    

After running the bash command, here’s a simplified extract of the terminal output

```bash
[Update database types/update]   ✅  Success - actions/setup-node@v2.1.5
[Update database types/update] ⭐  Run npm run update-types
echo "$(cat src/types/supabase.ts)"
[Update database types/update]   🐳  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/2] user= workdir=
| 
| > billy@0.0.1 update-types /Users/lyqht/self-study/Billy
| > npx openapi-typescript "${SUPABASE_URL}/rest/v1/?apikey=${SUPABASE_ANON_KEY}" --version=2 --output src/types/supabase.ts
| 
| npx: installed 10 in 3.328s
| ✨ openapi-typescript 5.2.0
🚀 ***/rest/v1/?apikey=*** -> /Users/lyqht/self-study/Billy/src/types/supabase.ts [28ms]
| /**
|  * This file was auto-generated by openapi-typescript.
|  * Do not make direct changes to the file.
|  */
| 
| export interface paths {
|   "/": {
|     get: {
|       responses: {
|         /** OK */
|         200: unknown;
|       };
|     };
|   };
|   "/Bill": {
|     get: {
|     .... } // i won't show you all of it, but you will be able to see all these
[Update database types/update]   ✅  Success - npm run update-types
echo "$(cat src/types/supabase.ts)"
[Update database types/update] ⭐  Run check for file changes
[Update database types/update]   🐳  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/git_status] user= workdir=
| /var/run/act/workflow/git_status: line 2: git: command not found
[Update database types/update]   ⚙  ::set-output:: status=
[Update database types/update]   ✅  Success - check for file changes
```

If you run this, you can can see the output contains the paths portion for '/Bill' as a result of running the `update-types` script. This meant that it worked correctly 🎉 

⚠️ Remember that these changes happen on the docker instance itself, **you will not see any changes on your local folder**.

## Bonus: In Action

On 7 Apr 2022, I added 2 new tables, and my bot was a good boi.

![New definitions added to the src/types/supabase.ts file](https://cdn.hashnode.com/res/hashnode/image/upload/v1649298808363/45lUlgtw1.png)

Since publishing the original article, I also created a GitHub action that does what is listed above. Check it out [here](https://github.com/lyqht/generate-supabase-db-types-github-action)!

## That's a wrap folks! 🎉

![https://c.tenor.com/eoM1uCVuXtkAAAAM/yay-excited.gif](https://c.tenor.com/eoM1uCVuXtkAAAAM/yay-excited.gif)

Thank you for reading, hope you enjoyed the article!

If you find the article awesome, hit the *reactions* 🧡 and *share* it 🐦~

To stay updated whenever I post new stuff, follow me on [Twitter](https://twitter.com/estee_tey).