Supa-Fast API (Supabase FastAPI) : Building the API
Tags: python, database, tutorial
Published: 2022-01-12 16:13:04

> In this is the second part of the [series](https://aunicorndev.hashnode.dev/series/supafast-api), we will be looking at building the API using FastAPI and Supabase python client.



***
### Prerequisites

- Have a database set up on Supabase(can match the database set up in the [last](https://aunicorndev.hashnode.dev/supabase-fastapi-setting-up-supabase) tutorial)
- Comfortable with Python (including Virtual Environments)
- An Idea  of what Environment Variables are
- JSON format

***



## Setting up FastAPI 
 
<p>&nbsp;</p>

**FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.**
<p>&nbsp;</p>

### Installing python 3.7.5
> To get started , make sure you have python > 3.7 as the latest `supabase` client uses that.

  

Download python 3.7.5 from [here](https://www.python.org/downloads/release/python-375/).

  

Install it with the Add to path flag checkbox **enabled**.

  

![Install Python 3.7.5](https://cdn.hashnode.com/res/hashnode/image/upload/v1641721154772/IUD7ATOSa.png)


  

To list all the installed python on your system use the below command

<p>&nbsp;</p> 

```
> py -0  

Installed Pythons found by C:\Windows\py.exe Launcher for Windows
 -3.7-32 *
 -3.6-32


```
***

### Creating test FastAPI 

Navigate to the folder where you want to create your project and run the following commands

  

```
mkdir supafast-api

cd .\supafast-api\


```

  

Create and activate a Virtual Environment with the latest installed python using the given commands

  

```
virtualenv venv-supaFastApi --python=python3.7

.\venv-supaFastApi\Scripts\activate


```

  

Create an `api` folder in which the main login for the API will reside.. Name the file as `main.py`

  

> Note: Do not name the file other than [main.py](http://main.py/) as it is required for deployment.

  

```
mkdir api

cd .\api

cd. >main.py
```

  

```
pip install fastapi

pip install "uvicorn[standard]"
```

<p>&nbsp;</p> 

In the `main.py` file, add the code below and run the API using uvicorn to test if everything works properly.

  

```
#main.py

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def root():
    return {"message": "Hello World Test"}
```

  

```
uvicorn main:app --reload

http://127.0.0.1:8000/

```

  

A response similar to this should appear on the screen at `http://127.0.0.1:8000/`

```
// 20211127160738
// http://127.0.0.1:8000/

{
  "message": "Hello World Test"
}
```

  

> TIP : use [JSON Viewer Chrome Extension](https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh) to view prettified JSON in the browser.

  

Now that the test FastAPI is working, let's get started and add the Supabase Python client
to get data in the API.

  

  

* * *

  

  

## Using Data from Supabase

{% github supabase-community/supabase-py no-readme %}


  

###   

```
pip install supabase
```

  

We need to use the `SUPABASE_URL` as well as `SUPABASE_KEY` which will be present in the settings of the Supabase project that we created in the [first](https://aunicorndev.hashnode.dev/supabase-fastapi-setting-up-supabase) part of this series.

  

  

![Supabase Keys](https://cdn.hashnode.com/res/hashnode/image/upload/v1641720541476/oZ_nO5JYR.png)


```
#main.py

from fastapi import FastAPI
from supabase import create_client, Client
app = FastAPI()


url = YOUR_SUPABASE_URL
key = YOUR_SUPABASE_KEY

supabase: Client = create_client(url, key)
```

  

### Getting Data from Database

  

<iframe width="100%" height="500px" style="box-shadow: 0 2px 8px 0 rgba(63,69,81,0.16); border-radius:15px;" allowtransparency="true" allowfullscreen="true" scrolling="no" title="Embedded DrawSQL IFrame" frameborder="0" src="https://drawsql.app/none-390/diagrams/supafast-api/embed"></iframe>

  

  

  

This was the structure of the database in the Supabase and for the API ,we are going to add two endpoints in FastAPI...

  

*   To list down all the themes - **/themes**
*   To list down the monsters of a particular theme - **/monsters/?theme={theme\_name}**

  

```
#main.py

from fastapi import FastAPI
from supabase import create_client, Client
app = FastAPI()

url = YOUR_SUPABASE_URL
key = YOUR_SUPABASE_KEY

@app.get("/themes")
def themes():
    themes = supabase.table('themes').select('*').execute()
    return themes

@app.get("/monsters/")
def monsters(theme : str = "demo-theme-1"):
    monsters = supabase.table('monsters').select('*').eq('monsterTheme',theme).execute()
    return monsters 


```

  

For the URL `http://127.0.0.1:8000/themes` , the result would be

  

```
// 20211127163945
// http://127.0.0.1:8000/themes

{
  "data": [
    {
      "id": 1,
      "created_at": "2021-11-26T15:28:21+00:00",
      "monsterTheme": "demo-theme-1"
    },
    {
      "id": 2,
      "created_at": "2021-11-26T15:29:45+00:00",
      "monsterTheme": "demo-theme-2"
    },
    {
      "id": 3,
      "created_at": "2021-11-26T15:30:04+00:00",
      "monsterTheme": "demo-theme-3"
    },
    {
      "id": 4,
      "created_at": "2021-11-26T15:30:12+00:00",
      "monsterTheme": "demo-theme-4"
    },
    {
      "id": 6,
      "created_at": "2021-11-26T15:30:21+00:00",
      "monsterTheme": "demo-theme-5"
    }
  ],
  "status_code": 200
}
```

  

  

For the "monsters" endpoint, we need a query parameter, but in case we don't send a query parameter, we will have a default value set so that a response is available at the endpoint.

  

In the `main.py` above , we have a default set to *demo-theme-1*.. So in case the API call is to the endpoint `http://127.0.0.1:8000/monsters/` we will get the result as follows

  

```
// 20211129131036
// http://127.0.0.1:8000/monsters/

{
  "data": [
    {
      "id": 1,
      "created_at": "2021-11-27T02:47:11+00:00",
      "monsterName": "demo-monster-1",
      "monsterQuote": "demo-quote-1",
      "monsterTheme": "demo-theme-1",
      "monsterLevel": 5
    },
    {
      "id": 2,
      "created_at": "2021-11-27T02:49:03+00:00",
      "monsterName": "demo-monster-2",
      "monsterQuote": "demo-quote-2",
      "monsterTheme": "demo-theme-1",
      "monsterLevel": 10
    },
    {
      "id": 4,
      "created_at": "2021-11-27T02:50:21+00:00",
      "monsterName": "demo-monster-3",
      "monsterQuote": "demo-quote-3",
      "monsterTheme": "demo-theme-1",
      "monsterLevel": 20
    }
  ],
  "status_code": 200
}
```

  

  

* * *

  

### Getting Images from Storage

  

The Supabase Python Client also provides various methods to interact with the Supabase Storage and we are going to get the public URL for the stored images.

  

For that we need to have the exact location of the file in the Bucket as well as the correct name for the images.

  


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640292359675/cwj3C-fL6.png)

  

From the last blog of the series, we had the above structure of files in the Bucket `supafast-api`

  

```
#main.py

from fastapi import FastAPI
from supabase import create_client, Client
app = FastAPI()

url = YOUR_SUPABASE_URL
key = YOUR_SUPABASE_KEY

supabase: Client = create_client(url, key)

@app.get("/themes")
def themes():
    themes = supabase.table('themes').select('*').execute()

    for theme in themes['data']:
#theme['monsterThemeBg'] = supabase.storage().StorageFileAPI(BUCKET_NAME).get_public_url(FILE_LOCATION)
        theme['monsterThemeBg'] = supabase.storage().StorageFileAPI('supafast-api').get_public_url('themes/'+ theme['monsterTheme'].replace(' ','-') + '.png')

    return themes


```

  

Here, the *FILE_LOCATION*  is easier to construct because the way these files are stored. The response we receive after adding the `monsterThemeBg` is like

  

```
// 20211129184109
// http://127.0.0.1:8000/themes

{
  "data": [
    {
      "id": 1,
      "created_at": "2021-11-26T15:28:21+00:00",
      "monsterTheme": "demo-theme-1",
      "monsterThemeBg": "https://jtpcokcjjqbizziufohl.supabase.co/storage/v1/object/public/supafast-api/themes/demo-theme-1.png"
    },
    {
      "id": 2,
      "created_at": "2021-11-26T15:29:45+00:00",
      "monsterTheme": "demo-theme-2",
      "monsterThemeBg": "https://jtpcokcjjqbizziufohl.supabase.co/storage/v1/object/public/supafast-api/themes/demo-theme-2.png"
    },
    
    ...


  ],
  "status_code": 200
}
```

  

  

The final `main.py` file will look something like this..

  

```
#main.py

from fastapi import FastAPI
from supabase import create_client, Client
app = FastAPI()

url = YOUR_SUPABASE_URL
key = YOUR_SUPABASE_KEY
supabase: Client = create_client(url, key)


@app.get("/themes")
def themes():
    themes = supabase.table('themes').select('*').execute()
    print(themes['data'])
    for theme in themes['data']:
        theme['monsterThemeBg'] = supabase.storage().StorageFileAPI('supafast-api').get_public_url('themes/'+ theme['monsterTheme'] + '.png')
    
    return themes

@app.get("/monsters/")
def monsters(theme : str = "demo-theme-1"):
    monsters = supabase.table('monsters').select('*').eq('monsterTheme',theme).execute()
    for monster in monsters['data']:
        monster['monsterBg'] = supabase.storage().StorageFileAPI('supafast-api').get_public_url(monster['monsterTheme']+'/'+ monster['monsterName'].replace(' ','-') + '.png')

    return monsters


```

  

  

* * *

Setting Up Environment Variables
--------------------------------



  

  

As you can see in the `main.py` , _SENSITIVE properties_ like the url and key are directly defined in the file. Such sensitive data should never be in a file and to overcome it, we use **environment variables.**

  

I found this really good article on [dev.to](https://dev.to/jakewitcher/using-env-files-for-environment-variables-in-python-applications-55a1) to use environment variables from a `.env` file.

  

To do that,

  

```
//Stop the uvicorn server

cd. >.env 
```

  

Now in the newly created `.env` file, add your variables in the format

  

```
#.env

SUPABASE_SUPAFAST_URL=your-supabase-url
SUPABASE_SUPAFAST_KEY=you-supabase-key

#make sure you don't have spaces before/after the equal sign
```

  

In `main.py` file,

  

```
import os
from fastapi import FastAPI
from supabase import create_client, Client
from dotenv import load_dotenv

load_dotenv()
app = FastAPI()

url = os.getenv('SUPABASE_SUPAFAST_URL')
key = os.getenv('SUPABASE_SUPAFAST_KEY')
supabase: Client = create_client(url, key)

'''
Rest of the code for the routes of the API
'''



```

  

  

Here, we additionally import the `os` and the `load_dotenv` packages, run the `load_dotenv()` function which loads the _KEY=VALUE_  pairs into the environment so that `os.getenv('KEY')` can retrieve the value from the environment.

  

> We didn't need to install a package for load\_dotenv because the `python-dotenv` gets automatically installed when running pip install "uvicorn\[standard\] "

  
***

  

In case you use git(or some other VCS), make sure to put the `.env` in the `.gitignore` file, so that it is not visible to the general public.

  

  



---
## Next Steps

Now that we have our API fully working on our local environment, in the next tutorial will deploy it on **DETA** and make it available publicly.

In case you have any doubts or suggestions regarding the article, feel free to contact me on my email aunicorndeveloper@gmail.com or on Twitter at [@aUnicornDev](https://twitter.com/aUnicornDev).



The API built in this series is used in the tabsMonster project. Everyone is more than welcome to checkout and contribute in this Open Source Project.


{% github aUnicornDev/tabsMonster no-readme %}



### Important Links 
Below are the links for docs and products if you are more interesed.

- [Python 3.7.5](https://www.python.org/downloads/release/python-375/)

- {% github tiangolo/fastapi no-readme %}

- [JSON Viewer Chrome Extension](https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh)




***




### Thank you for reading this far



![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1641723425513/UgtR-nqeN.png)